GetResponseAsync 不接受取消令牌 [英] GetResponseAsync does not accept cancellationToken

查看:16
本文介绍了GetResponseAsync 不接受取消令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆