我有一个控制台应用程序,它使用 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?
DelegatingHandler 有一个 protected 构造函数,它为内部处理程序接受一个处理程序。如果您可以控制所有自定义处理程序,我认为您可以添加一个调用受保护构造函数的公共构造函数,例如:
public class CustomHandler : DelegatingHandler
{
public CustomHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
}
并将它们链接起来:
var client = new HttpClient(
new CustomHandler(
new OtherCustomerHandler(
new HttpClientHandler()
)
)
);
我想你可以这样做:
var loggingHandler = new LoggingHandler();
var responseContentProcessingHandler = new ResponseContentProcessingHandler();
loggingHandler.InnerHandler = responseContentProcessingHandler;
var client = new HttpClient(loggingHandler);
因此您不需要仅为链接目的创建 CustomHandler。 这就是 DelegatingHandler 的真正目的。
如果使用 AddHttpClient 扩展方法,您可以使用
IHttpClientBuilder
来配置 DelegateHandler
-s 的所有链。
ServiceCollection
.AddHttpClient("MyClient")
.ConfigureHttpMessageHandlerBuilder(builder =>
{
builder.AdditionalHandlers.Add(builder.Services.GetRequiredService<YourFirstHandler>());
builder.PrimaryHandler = builder.Services.GetRequiredService<YourLastHandler>();
});
}
要在 .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);
....
}
对于 .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);