在服务之间共享HttpClient



我正在处理一个Blazor项目,为了让我的问题更容易理解,我们可以说我使用了两种不同的服务来处理身份验证部分。它们与一个命名的httpclient一起在configservices启动方法中注册。

services.AddHttpClient("XBOWServicesApi", c =>
{
c.BaseAddress = new Uri(XBOWServicesApi);
});
services.AddSingleton<IService1, Service1>();
services.AddSingleton<IService2, Service2>();

服务1:封装RESTApi中可用的所有功能。它使用一个http客户端,该客户端是通过实例化的httpclientfactory在构造函数中设置的。这需要使用baseurl和Auth头进行设置才能工作。

public Service1(IHttpClientFactory clientFactory)
{
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

服务2:使用自定义AuthenticationStateProvider处理登录/注销功能。它有自己的http客户端,因此我可以为http客户端设置Auth Header。构造函数的工作方式与服务1相同。

public Service2(IHttpClientFactory clientFactory)
{
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

进行此构建的原因当然是我喜欢共享同一个http客户端,因此当在登录/注销方法中设置该客户端时,服务1在与api通信时将具有正确的auth头。

但是,客户端工厂每次都会提供一个新的实例,所以这永远不会起作用。

有什么办法吗?

/Henrik

您可以使用named client:

services.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
// Github API versioning
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
// Github requires a user-agent
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});

然后,只需使用相应的name参数调用CreateClient方法。

var client = _clientFactory.CreateClient("github");

每次调用CreateClient时:

  • 创建了一个新的HttpClient实例
  • 配置操作为呼叫

您可以在此处的Microsoft文档中找到更多详细信息。

当我阅读Microsoft IHttpClientFactory文档时:

每次从IHttpClientFactory获得HttpClient对象时返回新实例。但是每个HttpClient都使用IHttpClientFactory池化并重用的HttpMessageHandler为了减少资源消耗,只要HttpMessageHandler生存期尚未过期。

这能回答你的问题吗?

您可以使用HttpMessageHandlers在瞬态HttpClient之间共享作用域服务。

IHttpClient.CreateClient每次都返回一个新实例,但您可以注册一个HttpMessageHandler,如下所示:

services.AddScoped<HandlerData>();
services.AddTransient<HeaderHandler>();
services.AddHttpClient("XBOWServicesApi", c =>
{
c.BaseAddress = new Uri(XBOWServicesApi);
}).AddHttpMessageHandler<HeaderHandler>();

HeaderHandler类:

public class HeaderHandler : DelegatingHandler
{
private readonly IHttpContextAccessor httpContextAccessor;
public HeaderHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken )
{
var Data= this.httpContextAccessor.HttpContext.RequestServices.GetRequiredService<HandlerData>();
request.Headers.Add(Data.HeaderName, Data.HeaderValue);
return base.SendAsync(request, cancellationToken);
}
}

HandlerData类:

public class HandlerData
{
public string HeaderName { get; set; }
public string HeaderValue { get; set; }
}

服务代码:

public Service1(IHttpClientFactory clientFactory, HandlerData data)
{
data.HeaderName = "Header1";
data.HeaderValue = "Value";
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}
public Service2(IHttpClientFactory clientFactory)
{
//This will contain the same headers as Service1 as HandlerData is Scoped Service
this.httpClient = clientFactory.CreateClient("XBOWServicesApi");
}

或者,如果您需要创建与您请求的DI作用域相同的处理程序,也可以使用新的IHttpMessageHandlerFactory

参考:https://github.com/aspnet/HttpClientFactory/issues/166

相关内容

  • 没有找到相关文章

最新更新