【问题标题】:GetRequiredService and AddHttpClient freeze .NET console application (stack overflow)GetRequiredService 和 AddHttpClient 冻结 .NET 控制台应用程序(堆栈溢出)
【发布时间】:2021-11-03 12:09:14
【问题描述】:

在我的 .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&lt;IHttpClientFactory&gt;(); 需要更改为 serviceCollection.AddHttpClient();

.BuildServiceProvider() 是多余的。

【问题讨论】:

  • 运行 .NET 5 并更改以下行 container.ConfigureServices(serviceCollection); 在我的机器上运行良好。还有什么不在您的示例中吗?
  • 另外,在此示例中,您无需在自己的IOCContainer 中调用BuildServiceProvider()
  • 远射,cool 构造函数中是否有容器无法解析的内容?
  • 1.我决定升级我的视觉工作室,因为它有点落后(我会告诉你是怎么回事) .2。感谢 BuildServiceProvider 说明,我将删除它并查看提供程序在集合中是否不为空。 :) .3。升级后我会记下 .net 5 的东西。我想知道我在做什么。
  • 1. BuildServiceProvider 已删除。谢谢。 .2. AddHttpClient 没有做我认为它正在做的事情。谢谢。我认为这就是问题所在。

标签: c# asp.net-core dependency-injection


【解决方案1】:

您遇到的是由AddHttpClient&lt;IHttpClientFactory&gt; 注册引起的堆栈溢出异常。这会导致 MS.DI 无法检测到的循环依赖关系,从而导致不幸的堆栈溢出。

要了解为什么会发生这种情况,您需要查看code 对应的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&lt;TClient&gt; 的调用会导致委托注册。调用该委托时,将解析 IHttpClientFactory。从该IHttpClientFactory 创建一个HttpClient。但是,在您的情况下,您为 TClient 指定了 IHttpClientFactory,从而有效地替换了原始的 IHttpClientFactory 注册。这导致对s.GetRequiredService&lt;IHttpClientFactory&gt;() 的调用回调到自身,从而导致循环依赖和堆栈溢出。

您做错了什么是提供IHttpClientFactory 作为AddHttpClient&lt;TClient&gt;TClientAddHttpClient 旨在注册一个“客户端”类,该类将 HttpClient 作为直接依赖项。例如:

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

但是,您并不是这里唯一的过错方。微软应该做得更好,因为:

  • MS.DI 的循环依赖检测缺乏且过于简单,导致它错过了这种类型的循环依赖。
  • AddHttpClient&lt;TClient&gt; 方法不验证允许这种情况发生的前提条件。由于为AddHttpClient 提供抽象的TClient 是没有意义的,至少它应该阻止这种情况并引发异常。此外,将不包含 HttpClientTClient 注册为构造函数依赖项是没有意义的,因此也应该避免这种情况。

这意味着微软堆栈还有改进的空间;-)

【讨论】:

  • 美丽。非常感谢。多么惊人的反应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 2011-06-28
  • 2016-06-13
  • 2019-05-18
相关资源
最近更新 更多