GetResponseAsync 不接受取消令牌 [英] GetResponseAsync does not accept cancellationToken
问题描述
似乎 GetResponseAsync 不接受 Async/Await 中的取消令牌.所以问题是如何取消以下程序,前提是我需要从响应中收集 Cookie:
It seems that GetResponseAsync does not accept cancellationToken in Async/Await. So the question is how can I cancel the below procedure, provided I need to collect Cookies from response:
using (HttpWebResponse response = (HttpWebResponse) await request.GetResponseAsync())
{
cookies.Add(response.Cookies);
}
也欢迎使用替代代码来实现上述目的.
An alternative code to achieve the above is also welcome.
推荐答案
这样的事情应该可行(未经测试):
Something like this should work (untested):
public static class Extensions
{
public static async Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request, CancellationToken ct)
{
using (ct.Register(() => request.Abort(), useSynchronizationContext: false))
{
var response = await request.GetResponseAsync();
ct.ThrowIfCancellationRequested();
return (HttpWebResponse)response;
}
}
}
理论上,如果在 ct
上请求取消并且 request.Abort
被调用,await request.GetResponseAsync()
应该抛出一个 <代码>WebException.不过,IMO,在使用结果时明确检查取消总是一个好主意,以减轻竞争条件,所以我调用 ct.ThrowIfCancellationRequested()
.
In theory, if cancellation is requested on ct
and request.Abort
is invoked, await request.GetResponseAsync()
should throw a WebException
. IMO though, it's always a good idea to check for cancellation explicitly when consuming the result, to mitigate race conditions, so I call ct.ThrowIfCancellationRequested()
.
另外,我假设 request.Abort
是线程安全的(可以从任何线程调用),所以我使用 useSynchronizationContext: false
(我还没有验证那个).
Also, I assume that request.Abort
is thread-safe (can be called from any thread), so I use useSynchronizationContext: false
(I haven't verified that).
[UPDATED] 解决 OP 关于如何区分由取消和任何其他错误引起的 WebException
的评论.这是如何做到的,所以 TaskCanceledException
(派生自 OperationCanceledException
)将在取消时正确抛出:
[UPDATED] to address the OP's comment on how to differentiate between WebException
caused by cancellation and any other error. This is how it can be done, so TaskCanceledException
(derived from OperationCanceledException
) will be correctly thrown upon cancellation:
public static class Extensions
{
public static async Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request, CancellationToken ct)
{
using (ct.Register(() => request.Abort(), useSynchronizationContext: false))
{
try
{
var response = await request.GetResponseAsync();
return (HttpWebResponse)response;
}
catch (WebException ex)
{
// WebException is thrown when request.Abort() is called,
// but there may be many other reasons,
// propagate the WebException to the caller correctly
if (ct.IsCancellationRequested)
{
// the WebException will be available as Exception.InnerException
throw new OperationCanceledException(ex.Message, ex, ct);
}
// cancellation hasn't been requested, rethrow the original WebException
throw;
}
}
}
}
这篇关于GetResponseAsync 不接受取消令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!