How To Correctly Register FhirClient for Dependency Injection
To avoid socket exhaustion/,
you need to pool HttpClient
instances and inject them into FhirClient
. The
default constructor will instantiate its own HttpClient
, which can leak sockets
and cause latency spikes in your app.
You can use IHttpClientFactory
to help with this. See the
documentation
for all the nitty-gritty details.
Note that while this example considers the open source
FhirClient
library, you can use this pattern with anyHttpClient
wrapper that lets you inject theHttpClient
instance.
In your Startup
class:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var url = Configuration["FHIR_ROOT_URL"];
var settings = new FhirClientSettings
{
PreferredFormat = ResourceFormat.Json,
VerifyFhirVersion = false, // avoids calling /metadata on every request
PreferredParameterHandling = SearchParameterHandling.Lenient
};
// register a named HttpClient configured for FHIR
services.AddHttpClient("FhirHttpClient")
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() {
// FhirClient configures its internal HttpClient this way
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
});
services.AddTransient(ctx => {
// Get a new HttpClient that is using pooled socket handlers behind the scenes
var httpClient = ctx.GetRequiredService<IHttpClientFactory>()
.CreateClient("FhirHttpClient");
// inject it into your client
return new FhirClient(url, httpClient, settings);
});
}
}
Registering Custom Handlers
What if you are using a custom HttpMessageHandler
to do some authorization such
as adding a client credentialed bearer token?
You can still set that up with DI. Just make your custom handler inherit from
DelegatingHandler
so that the AddHttpClient
machinery can reuse the
inner-most HttpMessageHandler
.
public class CustomAuthHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var token = await GetTokenFromSomewhere()
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
return await base.SendAsync(request, cancellationToken);
}
}
Now you can configure the HttpClient
instances to be automatically wired up
with this handler.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// register your auth handler
services.AddTransient<WebAuthMessageHandler>();
// register a named HttpClient configured to use it
services.AddHttpClient("FhirHttpClient")
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() {
// FhirClient configures its internal HttpClient this way
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
})
.AddHttpMessageHandler<CustomAuthHandler>();
}
}