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:
Startup.cspublic 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
.
ClientCredentialHandler.cspublic 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.
Startup.cspublic 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>(); } }