15

Flurl states that using singleton client is recommended pattern:

HttpClient is intended to be instantiated once and re-used throughout the life of an application. Especially in server applications, creating a new HttpClient instance for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors.

But since Asp.Net Core 2.1 there are updated rules for HttpClient lifetime in Net Core 2.1.

When you use the HttpClientFactory to request a HttpClient, you do in fact get a new instance each time, which means we don’t have to worry about mutating it’s state. This HttpClient may (or may not) use an existing HttpClientHandler from the pool and therefore use an existing open connection.

How to modify Flurl to use IHttpClientFactory under hood? Should I create custom Flurl's settings.HttpClientFactory and there create HttpClient through MS IHttpClientFactory?

Karel Kral
  • 5,297
  • 6
  • 40
  • 50
  • For ASP .Net 2.1 and Flurl 2.0, it is not possible to instantiate a FlurlClient as Todd Menier suggested. – Rodrigo S. Teixeira Nov 29 '18 at 19:39
  • 1
    @RodrigoS.Teixeira That is technically correct, [the constructor required to do it this way was introduced in Flurl.Http 2.3.1, released last April](https://github.com/tmenier/Flurl/issues/298). Is something preventing you from upgrading? – Todd Menier Dec 06 '18 at 15:46

1 Answers1

19

First, it should be noted that MS's new HttpClientFactory is intended to be used in conjunction with ASP.NET Core 2.1 and its built-in DI container. If you're not injecting FlurlClients into controllers or service classes, and are instead using Flurl like this:

await url.GetJsonAsync();

then it's not even relevant. You should not implement Flurl's IHttpClientFactory to use MS's. It doesn't have the proper context to use the DI container and you'll end up resorting to service location, which is an anti-pattern. Those new socket pooling features you want to take advantage of actually live at a lower level:System.Net.Http.SocketsHttpHandler. Flurl uses HttpClientHander as its message handler by default, but luckily that's been rewritten in .NET Core 2.1 to defer all of its work to SocketsHttpHandler by default. In other words, if you're using Flurl in a .NET Core 2.1 app, you're already getting all the new socket management goodies that MS has been working on.

If you are using FlurlClient explicitly in an ASP.NET Core 2.1 app, as sort of a replacement for HttpClient, and would like to inject it into your classes while taking advantage of what MS's HttpClientFactory has to offer, I would suggest setting up HttpClientFactory in ConfigureServices exactly as prescribed by MS, and when you need a FlurlClient instance, use the constructor that takes an HttpClient instance. For example, when using the typed clients pattern, your service class might look like this:

public class MyService
{
    private readonly IFlurlClient _flurlClient;

    public MyService(HttpClient httpClient)
    {
        _flurlClient = new FlurlClient(httpClient);
    }
}
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • Sorry to necro this very old answer but I'm wondering: what does `DefaultHttpClientFactory` have to offer here, given that you've said that Flurl is already delegating socket pooling and refreshing of DNS queries to the BCL? Given the heaviness of `ServiceCollection.AddHttp()`, I'm kind of loathe to use it unless it's adding a bunch of value on top of Flurl. – Nick Cox Jul 15 '21 at 07:27
  • 1
    @NickCox Fair question. Flurl's HttpClientFactory is very narrow in purpose: it allows you to control the construction of the HttpClient and HttpMessageHandler used by FlurlClient. It's not at all concerned with caching instances, reusing sockets, etc. Only construction details. If you provide an HttpClient to the FlurlClient constructor like the example above, it's not used at all. It's only used when you don't, and FlurlClient will call it once (lazily) when it's needed. – Todd Menier Jul 16 '21 at 17:26