Configure HttpClientFactory to use data from the current request context

后端 未结 1 2047
独厮守ぢ
独厮守ぢ 2020-12-02 21:00

With the new HttpClientFactory in ASP.NET Core 2.1, it\'s quite easy to configure custom HTTP clients with things like base urls, default headers etc.

However, I hav

相关标签:
1条回答
  • 2020-12-02 21:34

    Working on this answer lead me to multiple answers. I think the first approach is what you are looking for, the second is a good alternative.

    In order to configure multiple clients you can use named clients. These clients are registered as transient. Use DI to get the service that has access to the request context.

    For that we need IHttpContextAccessor. In this case you don't have to register it yourself, because Identity already does that for you.

    Otherwise add the following line in startup:

    services.AddHttpContextAccessor();
    

    Next we can configure the named client "github":

    services.AddHttpClient("github", c =>
    {
        // access the DI container
        var serviceProvider = services.BuildServiceProvider();
        // Find the HttpContextAccessor service
        var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
        // Get the bearer token from the request context (header)
        var bearerToken = httpContextAccessor.HttpContext.Request
                              .Headers["Authorization"]
                              .FirstOrDefault(h => h.StartsWith("bearer ", StringComparison.InvariantCultureIgnoreCase));
    
        // Add authorization if found
        if (bearerToken != null)
            c.DefaultRequestHeaders.Add("Authorization", bearerToken);
    
         // Other settings
        c.BaseAddress = new Uri("https://api.github.com/");
        c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); // Github API versioning
        c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); // Github requires a user-agent
    });
    

    Call the client like this:

    public class MyController : ControllerBase
    {
        private readonly IHttpClientFactory _clientFactory;
    
        public MyController(IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory;
        }
    
        public async Task<ActionResult> StartCall()
        {
            var client = _clientFactory.CreateClient("github");
            var response = await client.GetAsync("/repos/aspnet/docs/issues");
        }
    }
    

    Another option is to use Typed clients. Here's a short example. For a full example check the link.

    Register IHttpContextAccessor:

    services.AddHttpContextAccessor();
    

    Create a typed client. I've added two options to add settings. One through the request context and one through a singleton class:

    public class GitHubService
    {
        public HttpClient Client { get; }
    
        public GitHubService(HttpClient client, HttpClientSettings httpClientSettings, IHttpContextAccessor httpContextAccessor)
        {
            var bearerToken = httpContextAccessor.HttpContext.Request
                                  .Headers["Authorization"]
                                  .FirstOrDefault(h => h.StartsWith("bearer ", StringComparison.InvariantCultureIgnoreCase));
    
            // Add authorization if found
            if (bearerToken != null)
                client.DefaultRequestHeaders.Add("Authorization", bearerToken);
    
            // Or the value from httpClientSettings:
            client.DefaultRequestHeaders.Add("Authorization", httpClientSettings.BearerToken);
    
            client.BaseAddress = new Uri("https://api.github.com/");
            client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); // GitHub API versioning
            client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); // GitHub requires a user-agent
    
            Client = client;
        }
    }
    

    Register the client:

    // The typed client is registered as transient with DI.
    services.AddHttpClient<GitHubService>();
    

    Please note, the code below is just an example. Since the token can't be persisted in the client, you can use the shared HttpClientSettings instead:

    services.AddSingleton<HttpClientSettings>();
    

    Where HttpClientSettings is:

    public class HttpClientSettings
    {
        public string BearerToken { get; set; }
    }
    

    You can use the client like this:

    public class MyController : ControllerBase
    {
        private readonly GitHubService _gitHubService;
    
        public MyController(GitHubService gitHubService)
        {
            _gitHubService = gitHubService;
        }
    
        public async Task<ActionResult> StartCall()
        {
            var response = await _gitHubService.Client.GetAsync("/repos/aspnet/docs/issues");
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题