看起来GetResponseAsync在Async/Await中不接受cancellationToken。那么问题是,如果我需要从响应中收集Cookies,我该如何取消下面的过程:
using (HttpWebResponse response = (HttpWebResponse) await request.GetResponseAsync())
{
cookies.Add(response.Cookies);
}
欢迎提供其他实现上述功能的代码。
看起来GetResponseAsync在Async/Await中不接受cancellationToken。那么问题是,如果我需要从响应中收集Cookies,我该如何取消下面的过程:
using (HttpWebResponse response = (HttpWebResponse) await request.GetResponseAsync())
{
cookies.Add(response.Cookies);
}
欢迎提供其他实现上述功能的代码。
这样的代码应该可以运行(未经测试):
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;
}
}
}
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;
}
}
}
}
public static async Task GetResponseAsync(
this HttpWebRequest request, CancellationToken ct)
{
using (ct.Register(request.Abort, false))
{
try
{
return (HttpWebResponse)await request.GetResponseAsync();
}
catch (Exception)
{
ct.ThrowIfCancellationRequested();
throw;
}
}
}
- Joseph LennoxWebException
的访问权限,它目前作为Exception.InnerException
可用。 - noseratio - open to workThrowIfCancellationRequested
在这里和成功完成的 HttpWebRequest.GetResponseAsync
竞争。我移除了前者,将其留给调用者来处理这个竞争条件(当 Extensions.GetResponseAsync
可能同时完成时,该条件仍然存在)。 - noseratio - open to workpublic static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken, Action action, bool useSynchronizationContext = true)
{
using (cancellationToken.Register(action, useSynchronizationContext))
{
try
{
return await task;
}
catch (Exception ex)
{
if (cancellationToken.IsCancellationRequested)
{
// the Exception will be available as Exception.InnerException
throw new OperationCanceledException(ex.Message, ex, cancellationToken);
}
// cancellation hasn't been requested, rethrow the original Exception
throw;
}
}
}
现在你可以在任何可取消的异步方法中使用你的取消标记。例如,WebRequest.GetResponseAsync:
var request = (HttpWebRequest)WebRequest.Create(url);
using (var response = await request.GetResponseAsync())
{
. . .
}
will become:
var request = (HttpWebRequest)WebRequest.Create(url);
using (WebResponse response = await request.GetResponseAsync().WithCancellation(CancellationToken.None, request.Abort, true))
{
. . .
}
Abort()
吗? - svickHttpClient
? - Paulo Morgado