在服务之间共享HttpClient

时间:2020-04-20 11:20:47

标签: c# asp.net-core service httpclient blazor

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

services.AddHttpClient("XBOWServicesApi", c =>
{
c.BaseAddress = new Uri(XBOWServicesApi);
});

services.AddSingleton<IService1, Service1>();
services.AddSingleton<IService2, Service2>();

服务1:包装REST Api中可用的所有功能。它使用通过实例化的httpclientfactory在构造函数中设置的http客户端。必须使用baseurl和Auth-header进行设置。

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

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

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

这种积累的原因当然是我想共享同一个http客户端,因此在登录/注销方法中设置它时,服务1与api通信时将具有正确的auth标头。

但是,客户端工厂每次都提供一个新实例,因此它将永远无法工作。

有什么想法如何处理吗?

/亨里克

3 个答案:

答案 0 :(得分:0)

当我读完Microsoft IHttpClientFactory docs时:

每次从IHttpClientFactory获取HttpClient对象时, 返回新实例。但是每个HttpClient使用一个 由IHttpClientFactory池化并重用的HttpMessageHandler 减少资源消耗,只要使用HttpMessageHandler的 寿命尚未到期。

这能回答您的问题吗?

答案 1 :(得分:0)

您可以使用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");
});

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

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

每次调用CreateClient

  • 已创建一个新的HttpClient实例。
  • 配置操作是 叫。

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

答案 2 :(得分:0)

您可以使用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