gpt4 book ai didi

C# 'Cannot access a disposed object' 访问 Slack WebAPI 时出错 - 线程或其他什么?

转载 作者:行者123 更新时间:2023-12-03 08:36:30 27 4
gpt4 key购买 nike

有人可以帮忙吗?我有点困惑

我正在使用 PostAsync 将消息发送到 Slack API。代码如下。

我试图获得正确的速率限制代码,因此在编写我认为正确的内容后,我尝试通过从 for 循环中一遍又一遍地调用代码来触发速率限制(在本例中为发布消息) 。该代码捕获了速率限制,并且似乎做了它应该做的事情(等到限制通过,然后重试),但随后我得到一个异常,通常但并不总是在下次调用它时。

异常(exception)是

Cannot access a disposed object.
Object name: 'System.Net.Http.StringContent'.

来源是System.Net.Http堆栈跟踪是:

   at System.Net.Http.HttpContent.CheckDisposed()
at System.Net.Http.HttpContent.CopyToAsync(Stream stream, TransportContext context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MyApp.MyForm.<SendMessageAsync>d__78.MoveNext() in
C:\Users\James\source\repos\MyApp\MyApp\Form1.cs:line 1314

此时我确信(嗯,99% 确信)问题出在 SendMessageAsync() .

我以为是Thread.Sleep但当我删除它时,它发生的次数较少,但仍然会发生。

我试图追踪它何时失败,几乎每次它似乎都来自 PostAsync() ,在运行速率限制代码并且函数退出后下次调用它;它可能曾经在 JsonConvert.DeserializeObject() 失败过,不是在速率限制之后立即,但我不能确定,因为我处于调试的早期阶段。

有人可以帮忙吗?这让我发疯...

这是代码(请原谅原始的异常处理,它仍在进行中) - 如果需要,我可以提供更多上下文。

    private static readonly HttpClient client = new HttpClient();

// sends a slack message asynchronously
public static async Task<Object> SendMessageAsync(string token, string APIMethod, Object msg, string contentType, Type returnType)
{
string content;
switch (contentType)
{
case "application/json":
default:
// serialize method parameters to JSON
content = JsonConvert.SerializeObject(msg);
break;
case "application/x-www-form-urlencoded":
var keyValues = msg.ToKeyValue();
if (keyValues != null)
{
var formUrlEncodedContent = new FormUrlEncodedContent(keyValues);
content = await formUrlEncodedContent.ReadAsStringAsync();
}
else
content = "";
break;
}

StringContent httpContent = new StringContent(content, Encoding.UTF8, contentType);

// set token in authorization header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

try
{
Object messageResponse;
bool doLoop;
do
{
doLoop = false;
// send message to API
var response = await client.PostAsync("https://slack.com/api/" + APIMethod, httpContent);

// fetch response from API
var responseJson = await response.Content.ReadAsStringAsync();

// convert JSON response to object
messageResponse = JsonConvert.DeserializeObject(responseJson, returnType);

dynamic genResponse = Convert.ChangeType(messageResponse, returnType); // https://stackoverflow.com/questions/972636/casting-a-variable-using-a-type-variable
if (genResponse.ok == false && genResponse.error == "ratelimited")
{
if (response.Headers.RetryAfter != null && response.Headers.RetryAfter.Delta != null)
{
Thread.Sleep((TimeSpan)response.Headers.RetryAfter.Delta);
doLoop = true;
}
}
} while (doLoop);

return messageResponse;
}
catch (Exception x) { throw x; }
}

最佳答案

您需要为每个请求创建一个新的StringContentPostAsync 将处理内容。

When a request completes, HttpClient disposes the request content so the user doesn't have to. This also ensures that a HttpContent object is only sent once using HttpClient (similar to HttpRequestMessages that can also be sent only once).

Why do HttpClient.PostAsync and PutAsync dispose the content?

public static async Task<Object> SendMessageAsync(string token, string APIMethod, Object msg, string contentType, Type returnType)
{
string content;
switch (contentType)
{
case "application/json":
default:
// serialize method parameters to JSON
content = JsonConvert.SerializeObject(msg);
break;
case "application/x-www-form-urlencoded":
var keyValues = msg.ToKeyValue();
if (keyValues != null)
{
var formUrlEncodedContent = new FormUrlEncodedContent(keyValues);
content = await formUrlEncodedContent.ReadAsStringAsync();
}
else
content = "";
break;
}

// vvvv --- Move this line from here --- vvvv
//StringContent httpContent = new StringContent(content, Encoding.UTF8, contentType);

// set token in authorization header
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

try
{
Object messageResponse;
bool doLoop;
do
{
doLoop = false;

// vvvv --- To here --- vvv
StringContent httpContent = new StringContent(content, Encoding.UTF8, contentType);

// send message to API
var response = await client.PostAsync("https://slack.com/api/" + APIMethod, httpContent);

// fetch response from API
var responseJson = await response.Content.ReadAsStringAsync();

// convert JSON response to object
messageResponse = JsonConvert.DeserializeObject(responseJson, returnType);

dynamic genResponse = Convert.ChangeType(messageResponse, returnType); // https://stackoverflow.com/questions/972636/casting-a-variable-using-a-type-variable
if (genResponse.ok == false && genResponse.error == "ratelimited")
{
if (response.Headers.RetryAfter != null && response.Headers.RetryAfter.Delta != null)
{
Thread.Sleep((TimeSpan)response.Headers.RetryAfter.Delta);
doLoop = true;
}
}
} while (doLoop);

return messageResponse;
}
catch (Exception x) { throw x; }
}

关于C# 'Cannot access a disposed object' 访问 Slack WebAPI 时出错 - 线程或其他什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63751026/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com