简体   繁体   中英

Share HttpClient between services

I am working on a Blazor project, and to make the question I have easier to understand, we can say that I am using two different services that handles the Authentication part. Those are registered in the configureservices startup method together with a named httpclient.

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

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

Service 1: Wraps all functionality available in a REST Api. It uses an http client which is set in the constructor via an instanciated httpclientfactory. This needs to be set with a baseurl and an Auth-header to work.

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

Service 2: Handles the login/logout functionality using a custom AuthenticationStateProvider. It has its own httpclient, so that I can set the Auth Header for the http client. The constructor works in the same way as for Service 1.

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

The reason for this build up is of course that I like to share the same http client, so when it is set in the login/logout methods, service 1 will have the correct auth header when communicating with the api.

However, the client factory provides a new instance everytime, so this will never work.

Any ideas how to handle this?

/Henrik

When I read through the Microsoft IHttpClientFactory docs :

Each time you get an HttpClient object from the IHttpClientFactory, a new instance is returned. But each HttpClient uses an HttpMessageHandler that's pooled and reused by the IHttpClientFactory to reduce resource consumption, as long as the HttpMessageHandler's lifetime hasn't expired.

Does that answer your question?

You can use 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");
});

Afterwards, just call CreateClient method with corresponding name parameter.

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

Each time CreateClient is called:

  • A new instance of HttpClient is created.
  • The configuration action is called.

You can find more details in Microsoft documentation here .

You can share scoped services between transient HttpClients by using HttpMessageHandlers.

IHttpClient.CreateClient returns a new instance every time, but you can register a HttpMessageHandler as shown below:

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

HeaderHandler Class:

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 Class:

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

ServicesCode:

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");
}

Alternatively, you can also use new IHttpMessageHandlerFactory if you need to create handlers that live in the same DI scope as you request:

Reference: https://github.com/aspnet/HttpClientFactory/issues/166

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM