Message Handlers

The FhirClient provides an option to add HttpMessageHandlers that hook into the HTTP request/response cycle. These handlers let you run custom logic immediately before a request is sent or directly after a response is received.

Adding extra headers

Often you need to add headers to outgoing requests (for example an authorization token), or to execute logic on every request. Implement a custom message handler to perform these tasks. The example below shows an AuthorizationMessageHandler implementation:

public class AuthorizationMessageHandler : HttpClientHandler
{
        public System.Net.Http.Headers.AuthenticationHeaderValue Authorization { get; set; }
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
                if (Authorization != null)
                        request.Headers.Authorization = Authorization;
                return await base.SendAsync(request, cancellationToken);
        }
}

Add that handler to a FhirClient instance like this:

var handler = new AuthorizationMessageHandler();
var bearerToken = "AbCdEf123456" //example-token;
handler.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
var client = new FhirClient(handler);
client.ReadAsync<Patient>("example");

Chaining Multiple MessageHandlers

You can chain multiple HttpMessageHandlers to combine functionality. Use DelegatingHandler to form a pipeline: each handler can inspect or modify the request before passing it to the next handler and inspect or modify the response returned by the inner handler. Typically the final handler is HttpClientHandler, which performs the network I/O.

For example, besides an AuthorizationMessageHandler you might add a LoggingHandler:

public class LoggingHandler : DelegatingHandler
{
        private readonly ILogger _logger;

        public LoggingHandler(ILogger logger)
        {
                _logger = logger;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
                _logger.Trace("Request: " + request);
                try
                {
                        // base.SendAsync calls the inner handler
                        var response = await base.SendAsync(request, cancellationToken);
                        _logger.Trace("Response: " + response);
                        return response;
                }
                catch (Exception ex)
                {
                        _logger.Error("Failed to get response: " + ex);
                        throw;
                }
        }
}

Source: https://thomaslevesque.com/2016/12/08/fun-with-the-httpclient-pipeline/

To combine the handlers, set the AuthorizationMessageHandler as the InnerHandler of the LoggingHandler (since LoggingHandler is a DelegatingHandler):

var authHandler = new AuthorizationMessageHandler();
var loggingHandler = new LoggingHandler()
{
        InnerHandler = authHandler
};
var client = new FhirClient("http://server.fire.ly", FhirClientSettings.CreateDefault(), loggingHandler);

This results in a pipeline where requests and responses flow through the LoggingHandler and then the AuthorizationMessageHandler before reaching the network layer.

OnBeforeRequest and OnAfterResponse

To make use OnBeforeRequest and OnAfterResponse features that were in use on the pre-SDK5 FhirClient, you can use the pre-defined HttpClientEventHandler. Use the OnBeforeRequest to add extra code before a request is executed by the FhirClient, and the OnAfterResponse event to add extra code that needs to be executed every time a response is received by the FhirClient:

using (var handler = new HttpClientEventHandler())
{
        using (FhirClient client = new FhirClient(testEndpoint, messageHandler: handler))
        {
                handler.OnBeforeRequest += (sender, e) =>
                {
                        e.RawRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "Your Oauth token");
                };

                handler.OnAfterResponse += (sender, e) =>
                {
                        Console.WriteLine("Received response with status: " + e.RawResponse.StatusCode);
                };
        }
}