HttpClientFactory in ASP.NET Core 2.1 (Part 2) Defining Named and Typed Clients

In my last post – An introduction to HttpClientFactory – I explained some of the reasons behind the creation of the feature. We looked at what problems it helps solve and then followed a very basic example showing how it can be used in a WebAPI application. In this post I want to dive into two other ways we can make use of it; returning named clients and typed clients.

IMPORTANT NOTE: the features shown here require the current nightly builds of the SDK and the .NET Core and ASP.NET Core libraries. I won’t cover how to get those in this post. Treat this as an early preview of how the feature will work so that you can begin planning where and how you will use it once 2.1 is publicly available. Unless you have an urgent need to try this out today, I’d recommend waiting until the 2.1 previews are released, hopefully within the next month or so.

Named Clients

In the first post I demonstrated how we could use the HttpClientFactory to get a basic HttpClient instance. That’s fine when you just need to make a quick request from a single place in your code. Often though you’ll want to make multiple requests to the same service, from multiple places in your code.

HttpClientFactory makes this slightly easier by providing the concept of named clients. With named clients you can create a registration which includes some specific configuration that will be applied when creating the HttpClient. You can register multiple named clients which can each come pre-configured with different settings.

To make this slightly more concrete, let’s look at an example. In my Startup.ConfigureServices method I’ll use a different overload of the AddHttpClient extension method which accepts two additional parameters. A name and an Action delegate taking a HttpClient. My ConfigureServices looks like this:

The first string parameter is the name used for this client registration. The Action<HttpClient> delegate allows us to configure our HttpClient when it is constructed for us. This is pretty handy as we can predefine a base address and some known request headers for example. When we ask for a named client, a new one is created for us and it’ll have this configuration applied each time.

To use this we can ask for a client by name when calling CreateClient as follows:

In this example we now have an instance of a HttpClient which has the base address set, so our GetStringAsync method can pass in the relative URI to follow the base address.

This named approach gives us some control over the configuration applied to the HttpClient which we receive. I’m not a huge fan of the magic strings here so if I were using named clients I’d likely have a static class containing string constants for the names of the clients. Something like this:

When registering (or requesting) a client we can then use the static class values, instead of the magic string:

This is pretty nice, but we can go a step further and look at using a custom typed client instead.

Typed Clients

Typed clients allow us to define custom classes which expect a HttpClient to be injected in via the constructor. These can be wired up within the DI system using extension methods on the IHttpClientBuilder or using the generic AddHttpClient method which accepts the custom type. Once we have our custom class, we can either expose the HttpClient directly or encapsulate the HTTP calls inside specific methods which better define the use of our external service. This approach also means we no longer have magic strings and seems quite reasonable.

Let’s look at a basic example. We’ll start by defining our custom typed client class:

This class needs to accept a HttpClient as a parameter on it’s constructor. For now we’ve set a public property with the instance of the HttpClient.

We then need to register this in ConfigureServices as follows:

Here we pass our MyGitHubClient type to the generic argument. As our custom typed class accepts a HttpClient this will be wired up within the factory to create us an instance with the appropriately configured HttpClient injected in. We can now update our controller to accept our typed client instead of an IHttpClientFactory:

Since our custom typed client exposes its HttpClient as a property we can use that to make HTTP calls directly.

Encapsulating the HttpClient

The final example I want to look at in this post is a case where we want to encapsulate the HttpClient entirely. This approach is most likely useful when we want to define methods which handle specific calls to our endpoint. At this point we could also encapsulate the validation of the response and deserialisation within each method so that it is handled in a single place.

In this case we’ve stored the HttpClient that gets injected at construction in a private readonly field. Instead of dependants of this class accessing the HttpClient directly, we have provided a GetRootDataLength method which performs the HTTP call and returns the length of the response. A trivial example but you get the idea!

I also updated the typed client to inherit from an interface. We can now update the controller to accept and consume the interface as follows:

We can now call the GetRootDataLength method as defined on our interface, without needing to interact with a HttpClient directly. Where this really shines is testing, we can now easily mock our IMyGitHubClient when we want to test this controller. Testing HttpClient in the past was a bit of a pain and took more lines of code than I generally like to provide a suitable mock.

To register this in our DI container our call in ConfigureServices becomes:

The AddHttpClient has a signature which accepts two generic arguments and wires up DI appropriately.


In this post we’ve explored some of the more advanced ways we can use the HttpClientFactory feature which allows us to create different HttpClient instances with specific named configurations. We then looked at the option of using typed clients which extends this to further support implementing our own classes, which accept a HttpClient instance. We can either expose that HttpClient directly or encapsulate the calls to the remote endpoint within this class.

In the next post we’ll take a look at another pattern we can use to apply an “outgoing request middleware” approach using DelegatingHandlers.

Other Posts in this Series

Part 1 – An introduction to HttpClientFactory
Part 2 – This post

  • Anderson GM

    Hi Steve,

    Really nice article with comprehensive samples. I always have a great time reading your blog.

    I was looking at the typed clients samples and I think it would be better to configure the HttpClient inside the constructor of the type, in this case, MyGitHubClient class instead of in the method ConfigureServices. What do you think?

    • Steve Gordon

      Hi Anderson,

      Thanks, I’m glad you enjoyed it.

      Good suggestion and in fact I believe Jeff Fritz mentioned the same thing on his live stream with Glenn Condron. It’s a preference thing, but not reason you couldn’t move the configuration into the typed client. I’d personally tend to lean that way myself as it keeps the ConfigureServices area cleaner. I actually meant to show that in the post but forgot to actually do so!


  • Christo Kolander

    Very Nice articles. Looking forward to the next one. Not really qualified to make a statement, but feels like this HttpClientFactory is giving us a lot of flexibility, as well as pinpoint accuracy.

    • Steve Gordon

      Thanks Christo. I’m very glad you enjoyed them.

  • Evert Mulder

    The current HttpClient has a HttpClientHandler constructor param, for setting thigs like ServerCertificateCustomValidationCallback. Any example how this might work with with the DI?

  • Tester

    Great article! Is this correct that there are no more features planned out of the box like deserialisation to an object? So libs like RestSharp are still necessary for advance usages. The only real benefit is the “client pooling” and lifetime handling?

    • Steve Gordon

      I’m not aware of anything specifically around deserialisation. You’d likely be able to some custom deserialisation within a typed client though. The main goals here are around registering and consuming clients more easily. The lifetime handling is also there initially to work around lack of proper DNS management with current handlers. In .NET Core 2.1 the new managed handler should reduce the necessity for that piece.

    • Ella Salford