Named HttpClient Registrations

Introduction

You're most likely familiar with HttpClient and its recommended usage, which involves calling one of the overloads of AddHttpClient. One thing that you may or may not have noticed is, even though you call the overload that takes a name for the client, it is not registered in the dependency injection (DI) container as such. So I went out to fix this!

So, what we want is that any named clients can be also registered with the DI container, which will allow us to retrieve them by the service type and key:

var googleClient = serviceProvider.GetRequiredKeyedService<HttpClient>("Google");

or:

public IActionResult Index([FromKeyedServices("Google")] HttpClient googleClient) { ... }

So, as of now, the only way to obtain the named client is by using IHttpClientFactory's CreateClient method:

var googleClient = serviceProvider.GetRequiredService<IHttpClientFactory>().CreateClient("Google");

Which is fine, but just takes some extra work. Let's see how we can circumvent this.

Implementation for .NET < 9

This is what I came up with, an extension method AddAsKeyed over IHttpClientBuilder:

public static class HttpClientBuilderExtensions
{
    public static IHttpClientBuilder AddAsKeyed(this IHttpClientBuilder builder)
    {
        ArgumentNullException.ThrowIfNull(builder, nameof(builder));
        ArgumentException.ThrowIfNullOrWhiteSpace(builder.Name, nameof(builder.Name));

        builder.Services.AddKeyedTransient(builder.Name, (sp, key) => sp.GetRequiredService<IHttpClientFactory>().CreateClient((string)key));

        return builder;
    }
}

Which we can use like this:

builder.Services.AddHttpClient("Google", static client =>
{
    builder.BaseAddress = new("https://google.com");
}).AddAsKeyed();

As you can see, it's very easy to implement and use, it just leverages the IHttpClientFactory, but keep in mind that you should only call it for a named service - otherwise, it would be pointless anyway!

.NET 9

Realising this limitation, .NET 9 introduced its own AddAsKeyed method, which you will be able to use as soon as .NET 9 comes out! The ticket that requested it is https://github.com/dotnet/runtime/issues/89755. The methods do similar things, but I understand that my implementation will only be needed for versions of .NET before 9.

Conclusion

As always, hope you find this useful! Let me know what you think!


Comments

  1. I was looking at this exact thing the other day. I can see why your solution totally works and it even matches what is being done in .NET 9 better than what I came up with. I'm not sure I understand why they are not adopting the AddKeyed* syntax that is already being used for scoped and singletons, though. I was thinking to create a method named AddKeyedHttpClient("...", ...) myself.

    ReplyDelete
    Replies
    1. You’re right, beats me too! But we can write one ourselves, that’s the beauty of .NET (Core)

      Delete

Post a Comment

Popular posts from this blog

Audit Trails in EF Core

.NET Cancellation Tokens

Domain Events with .NET