Search code examples
c#dependency-injection.net-corefactory-pattern

.NET Core AddHttpClient Dynamic Configuration


I'm using AddHttpClient extension to configure HttpClient used in my personal RestClient.

    public class RestClient : IRestClient
    {
        public RestClient(IRestClientSettings settings, HttpClient httpClient)
        {
            ...
        }
    }

    public class RestClientFactory
    {
        public IRestClient Create(IRestClientSettings settings)
        {
            // how to create IRestClient with above configuration??
        }
    }

    public static IServiceCollection AddServices(this IServiceCollection services)
    {
        services.AddHttpClient<IRestClient, RestClient>((provider, client) =>
        {
            // problem, this is always same binded instance, 
            // not the one provided in RestClientFactory
            var settings = provider.GetService<IRestClientSettings>(); 
            settings.ConfigureHttp(provider, client);
        });
    }

Everything is fine if I inject IRestClient in my services but the problem is when I want to dynamically create IRestClient using RestClientFactory to use custom configuration (not one provided by default DI binding for IRestClientSettings). How can I achieve that?

IRestClientSettings are just custom settings along with ConfigureHttp method where user can define custom HttpClient settings.


Solution

  • I've ended up using simplest solution by always creating IRestClient via IRestClientFactory.

    public class RestClientFactory : IRestClientFactory
        {
            protected IHttpClientFactory HttpClientFactory { get; }
            protected IServiceProvider ServiceProvider { get; }
    
            public RestClientFactory(IHttpClientFactory httpClientFactory, IServiceProvider serviceProvider)
            {
                HttpClientFactory = httpClientFactory;
                ServiceProvider = serviceProvider;
            }
    
            public IRestClient Create()
            {
                return Create(ServiceProvider.GetService<IRestClientSettings>());
            }
    
            public IRestClient Create(IRestClientSettings settings)
            {
                return new RestClient(
                    settings,
                    HttpClientFactory.CreateClient()
                );
            }
        }
    

    And DI configuration

    public static IServiceCollection AddDotaClientService(this IServiceCollection services)
        {
            services.AddTransient<IRestClient>(provider =>
            {
                var clientFactory = provider.GetService<IRestClientFactory>();
                return clientFactory.Create();
            });
    
            services.AddSingleton<IRestClientFactory, RestClientFactory>();
    
            return services;
        }