为什么这个 HttpClient 用法给我一个 "Cannot access a disposed object." 错误?
Why is this HttpClient usage giving me an "Cannot access a disposed object." error?
我稍微简化了代码,但基本上这一直给我一个 "Cannot access a disposed object." 错误,我无法弄清楚为什么?
我有多个任务 运行 同时执行 GET 然后解析一些 HTML 然后根据 GET 的结果执行 POST。
此代码的方法驻留在 return 具有结果的事件对象中,因此我认为我不能使用 await,因为该方法需要 return void?
foreach (Account accountToCheck in eventToCheck.accountsToRunOn)
{
Task.Run(() =>
{
HttpClientHandler handler = new HttpClientHandler();
CookieContainer cookies = new CookieContainer();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
client.Timeout = new TimeSpan(0, 0, 3);
client.DefaultRequestHeaders.Add("Keep-Alive", "false");
HttpResponseMessage response = client.GetAsync("https://test.com", HttpCompletionOption.ResponseContentRead).Result;
string html = response.Content.ReadAsStringAsync().Result;
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("test[username_or_email]", accountToLogIn.accountHandle),
new KeyValuePair<string, string>("test[password]", accountToLogIn.accountPassword)
});
var loginPostResult = client.PostAsync("https://test.com/login", content).Result;
loginHTMl = convertToUTF8(loginPostResult.Content.ReadAsStringAsync().Result);
}
});
}
异常。
Unable to read data from the transport connection: Cannot access a disposed object.
好的,经过一些研究我发现了问题。 HttpClientHandler 将在第一个请求后被释放。您需要指示您的系统不要处理处理程序。
更改您的使用以将 false
添加到构造函数。
using (var client = new HttpClient(handler, false))
{
}
重用 HttpClientHandler 实例以防止处置是一个好习惯。
此外,我个人更喜欢更清晰的语法,尽量减少 Task.Result 调用。
// single setup of client handler
HttpClientHandler handler = new HttpClientHandler();
var tasks = eventToCheck.accountsToRunOn.Select(async () => {
// ...
using (var client = new HttpClient(handler, false)) // pass false to prevent Disposing
{
// ...
var html = await response.Content.ReadAsStringAsync();
// ...
return loginHtml;
}
});
// get array of results
string[] loginsHtml = await Task.WhenAll(tasks);
如果我们使用容器来注入 HttpClient 的依赖项,则不需要“使用”。容器会自己管理生命周期
我遇到的另一种情况是在操作 Azure Function 时。当超时到期时,无论您使用什么服务,您都会收到这样的消息。
我稍微简化了代码,但基本上这一直给我一个 "Cannot access a disposed object." 错误,我无法弄清楚为什么?
我有多个任务 运行 同时执行 GET 然后解析一些 HTML 然后根据 GET 的结果执行 POST。
此代码的方法驻留在 return 具有结果的事件对象中,因此我认为我不能使用 await,因为该方法需要 return void?
foreach (Account accountToCheck in eventToCheck.accountsToRunOn)
{
Task.Run(() =>
{
HttpClientHandler handler = new HttpClientHandler();
CookieContainer cookies = new CookieContainer();
handler.CookieContainer = cookies;
using (var client = new HttpClient(handler))
{
ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
client.Timeout = new TimeSpan(0, 0, 3);
client.DefaultRequestHeaders.Add("Keep-Alive", "false");
HttpResponseMessage response = client.GetAsync("https://test.com", HttpCompletionOption.ResponseContentRead).Result;
string html = response.Content.ReadAsStringAsync().Result;
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("test[username_or_email]", accountToLogIn.accountHandle),
new KeyValuePair<string, string>("test[password]", accountToLogIn.accountPassword)
});
var loginPostResult = client.PostAsync("https://test.com/login", content).Result;
loginHTMl = convertToUTF8(loginPostResult.Content.ReadAsStringAsync().Result);
}
});
}
异常。
Unable to read data from the transport connection: Cannot access a disposed object.
好的,经过一些研究我发现了问题。 HttpClientHandler 将在第一个请求后被释放。您需要指示您的系统不要处理处理程序。
更改您的使用以将 false
添加到构造函数。
using (var client = new HttpClient(handler, false))
{
}
重用 HttpClientHandler 实例以防止处置是一个好习惯。
此外,我个人更喜欢更清晰的语法,尽量减少 Task.Result 调用。
// single setup of client handler
HttpClientHandler handler = new HttpClientHandler();
var tasks = eventToCheck.accountsToRunOn.Select(async () => {
// ...
using (var client = new HttpClient(handler, false)) // pass false to prevent Disposing
{
// ...
var html = await response.Content.ReadAsStringAsync();
// ...
return loginHtml;
}
});
// get array of results
string[] loginsHtml = await Task.WhenAll(tasks);
如果我们使用容器来注入 HttpClient 的依赖项,则不需要“使用”。容器会自己管理生命周期
我遇到的另一种情况是在操作 Azure Function 时。当超时到期时,无论您使用什么服务,您都会收到这样的消息。