Search code examples
autofachttpclientfactory

Autofac fails to resolve enumerable of typed HttpClients


I have a number of services which require usage of typed HttpClient from HttpClientFactory. Though I can resolve one service I can't resolve IEnumerable of this services.

interface IMyHttpClient
{
}

class MyHttpClient: IMyHttpClient
{
    public MyHttpClient(HttpClient client)
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        var services = new ServiceCollection();
        services.AddHttpClient()
                .AddHttpClient<IMyHttpClient, MyHttpClient>();

        var builder = new ContainerBuilder();
        // Exception goes away when remove this line
        builder.RegisterType<MyHttpClient>().As<IMyHttpClient>();
        builder.Populate(services);
        var provider = builder.Build();

        // ============== This works
        // provider.Resolve<IMyHttpClient>();

        // ============== This throws exception
        provider.Resolve<IEnumerable<IMyHttpClient>>();
    }
}

Constructor will be called once and than exception is thrown:

``` DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ConsoleApp2.MyHttpClient' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Net.Http.HttpClient client' of constructor 'Void .ctor(System.Net.Http.HttpClient)'.

```

The issue is that AddHttpClient adds it's own registration of IMyHttpClient. But I do want to register using Autofac only! Is there a way to use typed clients but still stay with Autofac?


Solution

  • The exception explains that Autofac can't resolve parameter 'System.Net.Http.HttpClient client'. I suppose this is because such type wasn't registered in your container for second resgistration of IMyHttpClient. To save an advantages of HttpClientFactory you can register excplicit constructor parameter for example like this:

    static void Main(string[] args)
    {
        var services = new ServiceCollection();
        services.AddHttpClient();
    
        var builder = new ContainerBuilder();
        // exclicit resolving client for constructor
        builder.RegisterType<MyHttpClient>().As<IMyHttpClient>().WithParameter(
            (p, ctx) => p.ParameterType == typeof(HttpClient), 
            (p, ctx) => ctx.Resolve<IHttpClientFactory>().CreateClient());
    
        builder.Populate(services);
        var provider = builder.Build();
    
        // ============== This works
        provider.Resolve<IMyHttpClient>();
    
        // ============== This works too
        provider.Resolve<IEnumerable<IMyHttpClient>>();
    }
    

    In this example Resolve<IEnumerable<IMyHttpClient>> return enumeration with single IMyHttpClient, that is initialized with HttpClient from core HttpClientFactory.

    UPD: the post was updated by @norekhov comment