在等待base.SendAsync之后,Custom DelegatingHandler永远不会返回

时间:2012-10-25 02:37:54

标签: c# async-await dotnet-httpclient

我正在使用HttpClient构建API使用者。因为提供者要求使用者使用摘要式身份验证进行身份验证,所以我需要编写一个自定义DelegatingHandler,如下所示:

public class DigestAuthDelegatingHandler : DelegatingHandler
{
    public DigestAuthDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
        if (!response.IsSuccessStatusCode && response.StatusCode == HttpStatusCode.Unauthorized)//This line of code is never reached
        {
            //Generate the Digest Authorization header string and add to the request header,
            //then try to resend the request to the API provider
        }
        return response;
    }
}

我创建了一个HttpClient并将我的自定义DelegatingHandler添加到消息处理程序pineline

HttpClient httpClient = new HttpClient(new DigestAuthDelegatingHandler(new HttpClientHandler()));            
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.BaseAddress = new Uri("http://127.0.0.1/");
HttpResponseMessage response = httpClient.GetAsync("api/getTransactionInfo?TransactionNumber=1000).Result;   

在这样做之后,看起来我的消费者永远都会跑。当我在代码行等待base.SendAsync之后添加一个断点时,我发现代码永远不会返回,所以我无法检查响应是否获得401未经授权的提取摘要授权标题详细信息。 API提供商没有错,因为我已经使用传统的WebHttpRequest支持Digest Authenticate成功构建了另一个API使用者网站,并且运行良好。

重要说明:如果我切换到将消费者作为控制台应用程序编写,那么它运行良好。所以,我不确定,但我认为在异步模式下运行时,它与ASP.NET线程有关吗?

我在做什么事吗?

3 个答案:

答案 0 :(得分:1)

我同意Darrel - 最有可能的是,任务出现故障并且没有结果......您可以使用显式延续来检查任务状态 - 例如,

return base.SendAsync(request, cancellationToken).ContinueWith(task =>
    {
        // put the code to check the task state here...
    });

另据说明,我不确定您是否需要创建自定义DelegatingHandler进行身份验证...尝试使用HttpClientHandler Credentials属性(或UseDefaultCredentials传递当前用户的默认凭据)

var httpClient = new HttpClient(new HttpClientHandler() {
       PreAuthenticate = true,
       Credentials = new NetworkCredentials(...
   }); 

编辑:找到使用凭据缓存与http客户端一起使用摘要式身份验证的示例 - 请参阅此SO Q&amp;答:HttpRequestMessage and Digest Authentication

这应该解决你的实际问题w.r.t.摘要身份验证,无需构建自己的处理程序。

答案 1 :(得分:0)

我的猜测是.Result阻止了你的处理程序中的延续。尝试将.Result更改为.ContinueWith

答案 2 :(得分:0)

遇到同样的问题,这就是我最终的工作。问题是端点抛出了500内部服务器错误,因此阻止了线程。

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return await base.SendAsync(request, cancellationToken)
                         .ContinueWith<HttpResponseMessage>(task =>
        {
            return task.Result;
        });
    }

请注意,anon函数内部的返回返回SendAsync函数,然后我们实际返回Result。