如何在没有 HttpClientFactory 的情况下向 HttpClient 添加多个 HttpMessageHandler

问题描述 投票:0回答:5

我有一个控制台应用程序,它使用 HttpClient 发出 Web 请求。

var client = new HttpClient();

我正在尝试向其中添加多个 HttpMessageHandler(实际上是 DelegatingHandler 的自定义实现)但是 HttpClient构造函数只需要一个 HttpMessageHandler

class LoggingHandler : DelegatingHandler { //... }
class ResponseContentProcessingHandler : DelegatingHandler { //... }

这没关系...

var client = new HttpClient(new LoggingHandler()); // OK

但这不编译:

var client = new HttpClient(
                new LoggingHandler(), 
                new ResponseContentProcessingHandler()); // Sadness

因为我的目标是.NET 4.0,所以我不能使用HttpClientFactory,这个问题的解决方案通常是这样解释的:

HttpClient client = HttpClientFactory.Create(
                       new LoggingHandler(),
                       new ResponseContentProcessingHandler());

因为我只是在控制台应用程序中,而不是在 ASP.NET 应用程序中,所以我也不能这样做:

GlobalConfiguration.Configuration
                   .MessageHandlers
                   .Add(new LoggingHandler()
                   .Add(new ResponseContentProcessingHandler());

我查看了 HttpClientFactory 的源代码,里面似乎没有任何东西不能在 .NET 4.0 中编译,但没有启动我自己的工厂(“受微软源代码的启发”),有没有办法手动将许多 HTTP 消息处理程序添加到HttpClient

c# .net dotnet-httpclient
5个回答
32
投票

DelegatingHandler 有一个 protected 构造函数,它为内部处理程序接受一个处理程序。如果您可以控制所有自定义处理程序,我认为您可以添加一个调用受保护构造函数的公共构造函数,例如:

public class CustomHandler : DelegatingHandler
{
    public CustomHandler(HttpMessageHandler innerHandler) : base(innerHandler)
    {
    }
}

并将它们链接起来:

var client = new HttpClient(
    new CustomHandler(
        new OtherCustomerHandler(
            new HttpClientHandler()
        )
    )
);

20
投票

我想你可以这样做:

var loggingHandler = new LoggingHandler();
var responseContentProcessingHandler =  new ResponseContentProcessingHandler();
loggingHandler.InnerHandler = responseContentProcessingHandler;
var client = new HttpClient(loggingHandler);

因此您不需要仅为链接目的创建 CustomHandler。 这就是 DelegatingHandler 的真正目的。


2
投票

如果使用 AddHttpClient 扩展方法,您可以使用

IHttpClientBuilder
来配置
DelegateHandler
-s 的所有链。

ServiceCollection
    .AddHttpClient("MyClient")
    .ConfigureHttpMessageHandlerBuilder(builder =>
    {
        builder.AdditionalHandlers.Add(builder.Services.GetRequiredService<YourFirstHandler>());
        builder.PrimaryHandler = builder.Services.GetRequiredService<YourLastHandler>();
    });
} 

1
投票

要在 .Net 4.0 平台上使用控制台应用程序,最好的解决方案是将 httpConfiguration 传递给您的 webapi 库,或者如果您不持有 WebAPI 代码,只需将此代码写入 webhost asp.net 应用程序的 global.ascx 文件

     protected void Application_Start(object sender, EventArgs e)
             {
        var config = GlobalConfiguration.Configuration;
        WebAPIConfig.Configure(config);


    }

   //Code that will configure all message handlers in webapi    
          public static void Configure(HttpConfiguration configure)
   {


        configure.MessageHandlers.Add(new xyzhandler());
       configure.MessageHandlers.Add(new ABCHandler());

   }

在您的控制台应用程序中,放置您托管 webapi 的虚拟主机的 uri

   private const string APiUri="http://localhost/api/get"
   using(HttpClient cleint=new HttpClient()){
     var response await cleint.GetAsync(ApiUri);
    ....
               }

0
投票

对于 .NET C#,如果有人也想做类似的事情,我可以使用静态构建器/工厂将其存档:

namespace SomeNamespace {
  public class ConcreteDelegatingHandler : DelegatingHandler {}

  public class DelegateHandlerFactory
  {
    public static DelegatingHandler Build(dynamic[] handlers)
    {
      DelegatingHandler wrapper = new ConcreteDelegatingHandler();
      DelegatingHandler current = wrapper;
      HttpMessageHandler last = handlers.Last();

      foreach (dynamic handler in handlers)
      {
        if (handler == last)
          current.InnerHandler = handler;
        else if (current is DelegatingHandler)
        {
          current.InnerHandler = handler;
          current = handler;
        }
        else throw new InvalidOperationException("Intermediate handlers must be of type DelegatingHandler");
      }  
      return wrapper;
    }
  }
}

用法:

HttpMessageHandler[] handlers = {
  myDelegatingHandler1,
  myDelegatingHandler2,
  ...
  myDelegatingHandlerN
};

var handler = DelegateHandlerFactory.Build(handlers);
HttpClient Client = new HttpClient(handler, true);
© www.soinside.com 2019 - 2024. All rights reserved.