19

I want to add an HttClientHandler for a Typed HttpClient in order to include certificate authentication.

All the examples I'm finding on the internet are like this:

services.AddHttpClient<IMyService, MyService>()
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        return new HttpClientHandler()
        {
            // Set here whatever you need to get configured
        };
    });

But I don't want to include all the logic to obtain the certificate here, so I would like to use the generic version of ConfigurePrimaryHttpMessageHandler<> and write my own message handler to include the certificate in the request.

The problem is that I'm struggling to understand how should I implement the message handler... should I inherit from HttpClientHandler ??

Help, please!

Update

As I initially suspected, and @Nkosi confirmed, to derive from HttpClient handler is the way to go in this scenario. The code in the ends looks similar to this:

public class MyHttpClientHandler : HttpClientHandler
{
    private readonly IMyConfiguration _myConfiguration;

    public MyHttpClientHandler(IMyConfiguration myConfiguration)
    {
        _myConfiguration = myConfiguration;

        using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        {
            certStore.Open(OpenFlags.ReadOnly);
            var certCollection = certStore.Certificates.Find(
                X509FindType.FindBySerialNumber,
                _myConfiguration.MyCertificateSerial,
                true);

            X509Certificate2 certificate = certCollection[0];    
            ClientCertificateOptions = ClientCertificateOption.Manual;
            SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
            ClientCertificates.Add(certificate);
        }
    }
}

Very important!

On the other hand while trying to register my http client handler I noticed it was never being called. After some googling I found out that currently there's an open bug about that (https://github.com/aspnet/Extensions/issues/851). So until it get's fixed you need configure your handler this way:

services.AddTransient<MyHttpClientHandler>();

services.AddHttpClient<IMyService, MyService>()
    .ConfigurePrimaryHttpMessageHandler(sp => sp.GetRequiredService<MyHttpClientHandler>());
Manuel Navarro
  • 1,789
  • 2
  • 16
  • 18
  • derive from `HttpClientHandler` or any `HttpMessageHandler` derived class. https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.httpclientbuilderextensions.configureprimaryhttpmessagehandler?view=aspnetcore-2.2#Microsoft_Extensions_DependencyInjection_HttpClientBuilderExtensions_ConfigurePrimaryHttpMessageHandler__1_Microsoft_Extensions_DependencyInjection_IHttpClientBuilder_ – Nkosi Sep 10 '19 at 23:58
  • I understand `HttpClientHandler` is only for .NET Framework and Core <= 2.0. See [docs](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netcore-3.1). Need to use `HttpMessageHandler`. – Peter L Jul 07 '20 at 22:38

1 Answers1

20

Derive from HttpClientHandler or any HttpMessageHandler derived class.

public class MyHttpClientHandler : HttpClientHandler {

    public MyHttpClientHandler() {
        //Set here whatever you need to get configured
    }

    //...override members as needed
}

Call your handler using appropriate extension

services
    .AddHttpClient<IMyService, MyService>()
    .ConfigurePrimaryHttpMessageHandler<MyHttpClientHandler>();

The MyHttpClientHandler will be resolved from a scoped service provider that shares the lifetime of the handler being constructed.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Please refer to the update I added in the original post, as currently there's a bug at configuring primary Http message handlers using the generic version. – Manuel Navarro Sep 11 '19 at 17:08