在DelegatingHandler中使用HttpClient时出错:请求消息已发送。无法多次发送相同的请求消息

时间:2017-04-24 19:40:01

标签: c# dotnet-httpclient system.net

在下面的代码片段中,我尝试实现DelegatingHandler。您会注意到,在SendAsync方法中,我偏离了将请求传递给InnerHandler的传统做法......

base.SendAsync(request, cancellationToken);

...而是创建一个HttpClient的新实例,我传递了请求:

new HttpClient().SendAsync(request, cancellationToken);

这在像这样的裸骨片段中可能看起来很奇怪,但这里的想法是根据特定条件将请求传递给不同的HttpClientHandler,因此我需要能够动态地实例化HttpClient。

但是,当我运行此代码时,我收到以下异常:

The request message was already sent. Cannot send the same request message multiple times.

有人可以帮助我理解导致它的原因以及实现我的要求的更好方法(在处理程序中克隆请求而不是传递它,哪个有效,但看起来不优雅)?

using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace DelegatingHandlerTest
{
    internal static class Program
    {
        private static void Main()
        {
            var httpClient = new HttpClient(new MyTestHandler());

            var response = httpClient.GetAsync("http://icanhazip.com/").Result;

            Console.WriteLine(response.Content.ReadAsStringAsync().Result);
        }

    private class MyTestHandler : DelegatingHandler
    {

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return await new HttpClient().SendAsync(request, cancellationToken);
        }

    }
}

2 个答案:

答案 0 :(得分:0)

DelagatingHandler需要一个内部处理程序来运行,所以看起来你只需要确保在那里传递一个请求处理程序实例。

private static void Main()
{
      var httpClient = new HttpClient(new MyTestHandler(new HttpClientHandler()));

      var response = httpClient.GetAsync("http://icanhazip.com/").Result;

      Console.WriteLine(response.Content.ReadAsStringAsync().Result);
}


private class MyTestHandler : DelegatingHandler
{

      public MyTestHandler( HttpClientHandler handler) {
            base.InnerHandler = handler;
      }

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

}

答案 1 :(得分:0)

我可能会误解你的要求,但是如果你只需要在各种处理程序之间做出决定,你是否可以在调用base.SendAsync()之前将相应的HttpClientHandler分配给InnerHandler?像这样:

private class MyTestHandler : DelegatingHandler
{

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        if (someCondition)
        {
            base.InnerHandler = new MyHttpClientHandler(...);
        }

        else
        {
            base.InnerHandler = new MyOtherHttpClientHandler(...);
        }

        return await base.SendAsync(request, cancellationToken);

    }

}