Reputation: 101
IOperationContextProvider
to hold some information about my current execution context (called OperationContext
).For outgoing requests, I would like to configure to add the correlation ID to outgoing HTTP header, like this:
services.AddHttpClient<IMyClass, MyClass>((serviceProvider, httpClient) =>
{
var contextProvider = serviceProvider.GetRequiredService<IOperationContextProvider>();
var corrId = contextProvider.Context.CorrelationId;
httpClient.DefaultRequestHeaders.Add("x-corr-id", corrId);
});
However, I am unable to do this, because IHttpClientFactory creates scope for each handler it is creating and my context is not reachable from inside the HTTP client configuration. Same goes for adding HTTP message handlers, they are created in the same scope as the handler too.
The
IHttpClientFactory
creates a separate DI scope for each handler. Handlers are free to depend upon services of any scope.
Is there any way to reach the same scope as in which the HttpClient itself is being built?
I only have found a way to where for the MyClass
, where I also inject HttpClient
, I inject the IOperationContextProvider
too and configure manually the HttpClient
but that is a bit cumbersome because it needs to be done everywhere:
public MyClass(HttpClient httpClient, IOperationContextProvider contextProvider)
{
var corrId = contextProvider.Context.CorrelationId;
httpClient.DefaultRequestHeaders.Add("x-corr-id", corrId);
this._httpClient = httpClient;
}
Upvotes: 6
Views: 3984
Reputation: 21
One of the things thats also suggested is that the shared settings like the defaultrequestheaders be properly setup to avoid race conditions, if you are planning to use this client as a shared resource. This is in reference to your initial proposed workaround.
public MyClass(HttpClient httpClient, IOperationContextProvider
contextProvider)
{
var corrId = contextProvider.Context.CorrelationId;
httpClient.DefaultRequestHeaders.Add("x-corr-id", corrId);
this._httpClient = httpClient;
}
https://learn.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/
Upvotes: 2
Reputation: 387707
If you absolutely don’t want the HttpClientFactory to create a service scope, then you can disable this behavior through the HttpClientFactoryOptions.SuppressHandlerScope
property. There isn’t a nice API to configure this though, so you will have to do something like this:
var httpClientBuilder = services.AddHttpClient<IMyClass, MyClass>(…);
services.Configure<HttpClientFactoryOptions>(httpClientBuilder.Name, options =>
{
options.SuppressHandlerScope = true;
});
Alternatively, you could also create the delegating handler directly, without going through DI:
services.AddHttpClient<IMyClass, MyClass>(…)
.AddHttpMessageHandler(sp =>
{
var contextProvider = sp.GetService<IOperationContextProvider>()
return new MyHandlerWithoutDI(contextProvider);
});
Upvotes: 3