Search code examples
c#asp.net-core.net-coreasp.net-core-3.1ihttpclientfactory

Make ASP.NET core IHttpClientFactory throws when the requested named client is not defined


I'm working with ASP.NET core 3.1 and I'm writing a web api, starting from the Visual Studio 2019 built-in ASP.NET core web api template.

One of my services has a dependency on the IHttpClientFactory service. I'm using the named client consumption pattern. So, basically, I have code like this:

var client = _httpClientFactory.CreateClient("my-client-name");

I have noticed that the previous method call works even when using the name of a not existing HTTP client. By not existing HTTP client I mean a named HTTP client which has never been defined inside of the Startup.ConfigureServices method.

Put another way, I would expect the following code to throw, but actually it doesn't:

// code in Startup.ConfigureServices
services.AddHttpClient("my-client-name", c =>
{
  c.DefaultRequestHeaders.Add("User-Agent", "UserAgentValue");
});

// code in a custom service. I would expect this line of code to throw
var client = _httpClientFactory.CreateClient("not-existing-client");

Is it possible to configure an ASP.NET core 3.1 application so that the IHttpClientFactory has a strict behavior and code like the previous one throws an exception stating that the requested named client is not defined ?


Solution

  • Is it possible to configure an ASP.NET core 3.1 application so that the IHttpClientFactory has a strict behavior and code like the previous one throws an exception stating that the requested named client is not defined?

    Based on the source code for DefaultHttpClientFactory.Create

    public HttpClient CreateClient(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }
    
        HttpMessageHandler handler = CreateHandler(name);
        var client = new HttpClient(handler, disposeHandler: false);
    
        HttpClientFactoryOptions options = _optionsMonitor.Get(name);
        for (int i = 0; i < options.HttpClientActions.Count; i++)
        {
            options.HttpClientActions[i](client);
        }
    
        return client;
    }
    
    public HttpMessageHandler CreateHandler(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }
    
        ActiveHandlerTrackingEntry entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
    
        StartHandlerEntryTimer(entry);
    
        return entry.Handler;
    }
    

    What you describe is by design. If the client name does not exist a handler will just be added for the name used.