C# Flurl - Add WebRequestHandler to FlurlClient

2020-03-30 04:14发布

问题:

I am working with Flurl to hit an API that requires certificate-based authentication. I have seen from this SO post that adding a certificate to a WebRequestHandler and instructing an HttpClient to use this handler is easy.

However, it is not so clear for me using Flurl. I have tried the follwing three things.

Extending DefaultHttpFactory

I first suspected that I needed to create my own X509HttpFactory : DefaultHttpFactory which would create the handler and assign it to the HttpClient. However, in viewing the source, I notice that the constructor for CreateClient already expects a handler. Where does this handler come from?

Creating Client using DefaultHttpFactory

WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(myX509Cert);
var clientFactory = new DefaultHttpClientFactory();
FlurlClient fc = clientFactory.CreateClient(url, handler);

This does not compile as HttpClient cannot be casted to FlurlClient

Use ConfigureHttpClient

var clientFactory = new DefaultHttpClientFactory();
FlurlClient fc = new Url("foobar.com").ConfigureHttpClient(client => client = clientFactory
  .CreateClient(url, handler));

This seems like the most viable option, but I'm unsure since the delegate is an Action with no return type.

The Question

What is the best/correct way to support client-side certificate authentication using Flurl?

回答1:

You're close - a custom factory is definitely the way to go. But you want to override CreateMessageHandler rather than CreateClient:

public class X509HttpFactory : DefaultHttpClientFactory
{
    private readonly X509Certificate2 _cert;

    public X509HttpFactory(X509Certificate2 cert) {
        _cert = cert;
    }

    public override HttpMessageHandler CreateMessageHandler() {
        var handler = new WebRequestHandler();
        handler.ClientCertificates.Add(_cert);
        return handler;
    }
}

Then you can either register it globally (on app startup):

FlurlHttp.Configure(settings => {
    settings.HttpClientFactory = new X509HttpFactory(myCert);
});

Or for all calls to a particular host:

FlurlHttp.ConfigureClient(ROOT_URL, cli => {
    cli.Settings.HttpClientFactory = new X509HttpFactory(myCert);
});

Or for a new FlurlClient:

var cli = new FlurlClient(url)
    .Configure(settings => settings.HttpClientFactory = new X509HttpFactory(myCert));

Or an existing one:

cli.Settings.HttpClientFactory = new X509HttpFactory(myCert);