Reputation: 133
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?
Upvotes: 1
Views: 726
Reputation: 56
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.
Upvotes: 3
Reputation: 2693
You could use Polly to add a policy handler to your client. You can then add logic if a request returns a 401 Unauthorized. So for example get your service that uses the client to refresh a bearer token and also set it for the current request. This is just a quick solution and maybe there are more elegant solutions. But this will also come in handy if your token expires. Cause then it will be refreshed automatically.
services.AddHttpClient("YourClient")
.AddPolicyHandler((provider, request) =>
{
return Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(1, async (response, retryCount, context) =>
{
var service = provider.GetRequiredService<IYourService>();
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await service.RefreshToken());
});
});
Upvotes: 0