像这样的东西应该有效(未经测试):
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
and request.Abort
被调用,await request.GetResponseAsync()
应该抛出一个WebException
。不过,在 IMO 中,在使用结果时显式检查取消总是一个好主意,以减轻竞争条件,所以我调用ct.ThrowIfCancellationRequested()
.
另外,我假设request.Abort
是线程安全的(可以从任何线程调用),所以我使用useSynchronizationContext: false
(我还没有验证过)。
[更新]解决OP关于如何区分之间的评论WebException
因取消或任何其他错误而造成的。这是可以做到的,所以TaskCanceledException
(源自OperationCanceledException
) 将在取消时正确抛出:
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;
}
}
}
}