Search code examples
c#asp.net-corehttpclient

How to create named client after startup?


For my application i need to make a named client for HttpRequests. I can create a named client in Startup. And to access it i inject an "IHttpClientFactory" and create a client from that. But the client needs to have an access token as an authorization header, and i cannot create the token in Startup. Therefor i need a way to create a named client outside of the Startup class. i have already tried injecting "IServiceCollection" into a controller. But this does not work.

Or is there maybe a way to edit a named client after it is already created in startup?


Solution

  • A similar solution to the one posted by @Ruben-J is to create a custom HttpMessageHandler which assigns an authorization header to requests made through the HttpClient at request-time.

    You can create a custom HttpMessageHandler that can be assigned to a named HttpClient in Startup like so:

    public class YourHttpMessageHandler : DelegatingHandler
    {
        private readonly IYourTokenProviderService _yourTokenProviderService;
    
        public YourHttpMessageHandler(IYourTokenProviderService yourTokenProviderService) 
            : base()
        {
            _yourTokenProviderService = yourTokenProviderService;
        }
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = SendAsyncWithAuthToken(request, cancellationToken);
    
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                await _yourTokenProviderService.RefreshTokenAsync();
    
                response = SendAsyncWithAuthToken(request, cancellationToken);
            }
    
            return response;
        }
    
        private async Task<HttpResponseMessage> SendWithAuthTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _yourTokenProviderService.Token);
    
            return await base.SendAsync(request, cancellationToken);
        }
    }
    

    You then configure your services and named HttpClient in Startup:

    public virtual void ConfigureServices(IServiceCollection services) 
    {
        ...
        services.AddTransient<IYourTokenProviderService, YourTokenProviderService>();
        services.AddTransient<YourHttpMessageHandler>();
    
        services.AddHttpClient<IYourNamedHttpClient, YourNamedHttpClient>()
            .AddHttpMessageHandler<YourHttpMessageHandler>();
        ...
    }
    
    

    Its worth noting that the current implementation of Polly's AddPolicyHandler is also adding its own DelegatingHandler. For more background see the Microsoft documentation on adding DelegatingHandler's. Here is also great series of articles from Steve Gordon.