GetRequiredService и AddHttpClient замораживают .СЕТЕВОЕ консольное приложение (переполнение стека)

#c# #asp.net-core #dependency-injection

Вопрос:

В моем консольном приложении .NET Core эта строка зависает:

services.GetRequiredService<ISomething>();

в следующем коде:

 interface ISomething { }
class Cool : ISomething
{
    public Cool(IHttpClientFactory factory) { }
}

class Program
{
    static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        await host.StartAsync();

        // Freezes here and maxes out memory
        ISomething internalApiConnector = host.Services.GetRequiredService<ISomething>();

        await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((_, services) =>
            {
                services.AddHttpClient<IHttpClientFactory>();
                services.AddSingleton<ISomething, Cool>();
            });
}
 

и в конечном итоге исчерпывает память, что в конечном итоге приводит к сбою приложения.
Чего мне не хватает?

Примечание:

  • Cool конструктор не запускается, поэтому, похоже, там что-то не останавливается.

Решение (Всем спасибо):

serviceCollection.AddHttpClient<IHttpClientFactory>(); необходимо было изменить на serviceCollection.AddHttpClient();

и

.BuildServiceProvider() было очень много.

Комментарии:

1. Запуск .NET 5 и изменение следующей строки container.ConfigureServices(serviceCollection); отлично работает на моей машине. Что-нибудь еще, чего нет в вашем примере?

2. Кроме того, в этом примере нет никакой необходимости звонить BuildServiceProvider() самостоятельно IOCContainer .

3. В конечном счете, есть ли в cool конструкторе что-нибудь, что контейнер не может разрешить?

4. 1. Я решил обновить свою visual studio, так как она немного отстала (я расскажу вам, как это происходит) .2. Спасибо за примечание BuildServiceProvider, я удалю его и посмотрю, не является ли поставщик нулевым в коллекции. 🙂 .3. после обновления я отмечу .net 5. Интересно, на чем я сейчас?

5. 1. BuildServiceProvider удален. Спасибо. .2. AddHttpClient не делает то, что я думал, что он делает. Спасибо. Я думаю, в этом-то и проблема.

Ответ №1:

То, что вы испытываете, — это исключение переполнения стека, вызванное AddHttpClient<IHttpClientFactory> регистрацией. Это вызывает циклическую зависимость, которая не обнаруживается г-жой ДИ, что приводит к неудачному переполнению стека.

Чтобы понять, почему это происходит, вам нужно посмотреть код для HttpClientBuilderExtensions :

 builder.Services.AddTransient<TClient>(s =>
{
    var httpClientFactory = s.GetRequiredService<IHttpClientFactory>();
    var httpClient = httpClientFactory.CreateClient(builder.Name);

    var typedClientFactory = s.GetRequiredService<ITypedHttpClientFactory<TClient>>();
    return typedClientFactory.CreateClient(httpClient);
});
 

Как видно из кода, вызов AddHttpClient<TClient> приводит к регистрации делегата. Когда этот делегат вызывается, an IHttpClientFactory разрешается. Из этого IHttpClientFactory HttpClient создается an. В вашем случае, однако, вы указали IHttpClientFactory для себя TClient , фактически заменив первоначальную IHttpClientFactory регистрацию. Это привело к s.GetRequiredService<IHttpClientFactory>() обратному вызову в себя, отсюда циклическая зависимость и переполнение стека.

То, что вы сделали неправильно, — это поставка IHttpClientFactory в качестве TClient AddHttpClient<TClient> . AddHttpClient предназначен для регистрации класса «клиент», который принимает a HttpClient как прямую зависимость. Например:

 services.AddHttpClient<GitHubApiClient>() // GitHubApiClient depends on HttpClient
 

Однако вы здесь не единственная виноватая сторона. Microsoft должна была быть лучшей работой, потому что:

  • Обнаружение циклической зависимости г-жи ДИ отсутствует и слишком упрощено, из-за чего она пропускает этот тип циклической зависимости.
  • AddHttpClient<TClient> Метод не проверяет, что это предварительные условия, позволяющие этому произойти. Поскольку нет смысла AddHttpClient снабжать абстрактным TClient , по крайней мере, это должно было предотвратить это и создать исключение. Более того, нет смысла регистрировать a TClient , который не содержит HttpClient зависимости от конструктора as, поэтому этот случай также должен был быть предотвращен.

Это означает, что в стеке Microsoft есть возможности для улучшения 😉

Комментарии:

1. Красивые. Большое спасибо. Какая удивительная реакция.