#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
, по крайней мере, это должно было предотвратить это и создать исключение. Более того, нет смысла регистрировать aTClient
, который не содержитHttpClient
зависимости от конструктора as, поэтому этот случай также должен был быть предотвращен.
Это означает, что в стеке Microsoft есть возможности для улучшения 😉
Комментарии:
1. Красивые. Большое спасибо. Какая удивительная реакция.