Autofac не может разрешить перечислимые типизированные HttpClients

У меня есть ряд служб, которые требуют использования типизированного HttpClient из HttpClientFactory. Хотя я могу разрешить одну службу, я не могу разрешить IEnumerable из этих служб.

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>>();
    }
}

Конструктор вызывается один раз, после чего генерируется исключение:

`` DependencyResolutionException: ни один из конструкторов, обнаруженных с помощью 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' для типа 'ConsoleApp2.MyHttpClient', не может быть вызван с доступными службами и параметрами: Невозможно разрешить параметр 'System.Net.Http.HttpClient client 'конструктора' Void .ctor (System.Net.Http.HttpClient) '.

```

Проблема в том, что AddHttpClient добавляет собственную регистрацию IMyHttpClient. Но я хочу зарегистрироваться только с помощью Autofac! Есть ли способ использовать типизированные клиенты, оставаясь при этом с Autofac?


person norekhov    schedule 12.09.2018    source источник


Ответы (1)


Исключение объясняет, что Autofac не может разрешить параметр «Клиент System.Net.Http.HttpClient». Я полагаю, это связано с тем, что такой тип не был зарегистрирован в вашем контейнере для второй повторной регистрации IMyHttpClient. Чтобы сохранить преимущества HttpClientFactory, вы можете зарегистрировать параметр явного конструктора, например, следующим образом:

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>>();
}

В этом примере Resolve<IEnumerable<IMyHttpClient>> возвращает перечисление с одним IMyHttpClient, которое инициализируется HttpClient из основного HttpClientFactory.

UPD: пост обновлен комментарием @norekhov

person KozhevnikovDmitry    schedule 13.09.2018
comment
Да, именно об этом я и подумал. Вместо регистрации нескольких клиентов в домене ServiceCollection я помещу туда только .AddHttpClient, а затем разрешу параметры непосредственно внутри регистраций Autofac. Чем services.AddHttpClient<IMyHttpClient, MyHttpClient>(); можно заменить на services.AddHttpClient(); только для базовой регистрации. - person norekhov; 13.09.2018
comment
Если вам нужно просто разрешить HttpClient экземпляры с помощью ядра HttpClientFactory, да, это сработает для вас. - person KozhevnikovDmitry; 13.09.2018
comment
Обновлен ответ для предотвращения дублирования регистрации IMyHttpClient. - person KozhevnikovDmitry; 14.09.2018