Flurl: Delegate HttpClient creation to MS's HttpClientFactory

Created on 18 Sep 2019  路  5Comments  路  Source: tmenier/Flurl

Why not delegate the actual HttpClient creation to Microsoft's HttpClientFactory instead of creating the HttpClient in this library and trying to cache it internally. Let Microsoft handle that complexity.
The only downside here is that the name

    public class DelegatingFactory: IFlurlClientFactory
    {
        private readonly System.Net.Http.IHttpClientFactory _clientFactory;

        public DelegatingFactory(System.Net.Http.IHttpClientFactory clientFactory)
        {
            _clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
        }

        public void Dispose()
        {
            //...
        }

        public IFlurlClient Get(Url url)
        {
            return new FlurlClient(_clientFactory.CreateClient(url));
        }
    }

Then in Startup.cs you can register this as follows

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient("https://api.github.com/", c =>
            {
                c.BaseAddress = new Uri("https://api.github.com/");
                // Github API versioning
                c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
                // Github requires a user-agent
                c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
            });
            services.AddSingleton<IFlurlClientFactory, DelegatingFactory>();           
        }

The only downside being that the name of a named HttpClient has to be the baseUrl, but that is a requirement of Flurl, unfortunately.
With the above code you can still use named HttpClient as MS proposes and re-use those named clients as an IFlurlClient.

Basically I wanted to use named HttpClients as I was doing before and just re-use that configuration with Flurl.
Extending the IFlurlClientFactory interface to take names different from the BaseUrl would nice.

enhancement

Most helpful comment

a workaround that I'm using is using the HttpClient provided by IHttpClientFactory and using it in request, something like this:

"https://myawesomeapi.com.br/myawesomeresource".WithClient(new FlurlClient(myHttpClientFromIHttpClientFactory)).GetJsonAsync<MyAwesomeResource>();

I know maybe it's not the usual way neither fit all needs, but currently is the solution that i found to use the best part of this two worlds.

All 5 comments

Duplicate of #418?

No, not really, as Flurl doesn't support named HttpClients. I want the config of the HttpClient in DI (through AddHttpClient) instead of in a constructor. I don't approve of that solution proposed as it supports only plain HttpClients and not named HttpClients. I want DI to inject a factory that returns fully configured HttpClients/FlurlClients, instead of a factory that returns HttpClient that I still would have to configure.

Why not delegate the actual HttpClient creation to Microsoft's HttpClientFactory instead of creating the HttpClient in this library and trying to cache it internally. Let Microsoft handle that complexity.

For a little background, Flurl 2.0 (where IFlurlClientFactory and the caching stuff were introduced) pre-dates .NET Core 2.1, where MS's HttpClientFactory was introduced. Plus, it's not supported on all platforms that Flurl targets. And the really hard stuff is in down in HttpSocketsHandler, which you get for free if you're on .NET Core 2.1 or above.

3.0 is now in the works, and coming up with a way to do something similar to AddHttpClient was a popular request, so something will be done there that I think will satisfy your request. I always found named clients a little odd in that instance-per-named-key seems like a generic IoC concept that could be useful for lots of things, yet they made it very specific to HttpClient. So to make the same concept work with FlurlClient requires a little more reinventing of the wheel than I expected. At least that's the impression I got when I first looked into it a while back.

a workaround that I'm using is using the HttpClient provided by IHttpClientFactory and using it in request, something like this:

"https://myawesomeapi.com.br/myawesomeresource".WithClient(new FlurlClient(myHttpClientFromIHttpClientFactory)).GetJsonAsync<MyAwesomeResource>();

I know maybe it's not the usual way neither fit all needs, but currently is the solution that i found to use the best part of this two worlds.

Closing because the suggestion at the heart of it - using MS's HttpClientFactory in Flurl's implementation - would require Flurl take on some additional dependencies. I don't think people using it in Xamarin and other platforms/scenarios that are far removed from ASP.NET Core would appreciate that.

At some point I'd like to explore the possibility of building a companion lib (Flurl.Http.AspNetCore?) that takes those dependencies and integrates more directly with MS's IoC container to provide something like services.AddFlurlClient with some of the same patterns you get in ASP.NET Core. I think that's what people really want.

Was this page helpful?
0 / 5 - 0 ratings