c# - GetRequiredService 和 AddHttpClient 冻结 .NET 控制台应用程序(堆栈溢出)
问题描述
在我的 .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()
是多余的。
解决方案
您遇到的是由AddHttpClient<IHttpClientFactory>
注册引起的堆栈溢出异常。这会导致 MS.DI 未检测到的循环依赖关系,从而导致不幸的堆栈溢出。
要了解为什么会发生这种情况,您需要查看以下代码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>
导致委托注册。调用该委托时,将IHttpClientFactory
解析 an。从中创建IHttpClientFactory
一个HttpClient
。但是,在您的情况下,您指定IHttpClientFactory
了您的TClient
,有效地替换了原始IHttpClientFactory
注册。这导致对s.GetRequiredService<IHttpClientFactory>()
自身的回调调用,从而导致循环依赖和堆栈溢出。
你做错了什么是IHttpClientFactory
提供TClient
of AddHttpClient<TClient>
。AddHttpClient
旨在注册一个HttpClient
直接依赖的“客户端”类。例如:
services.AddHttpClient<GitHubApiClient>() // GitHubApiClient depends on HttpClient
但是,您并不是这里唯一有过错的一方。微软应该做得更好,因为:
- MS.DI 的循环依赖检测缺乏并且过于简单,导致它错过了这种类型的循环依赖。
- 该
AddHttpClient<TClient>
方法不验证允许这种情况发生的前提条件。由于提供AddHttpClient
abstract是没有意义的TClient
,至少它应该阻止这种情况并抛出异常。此外,注册一个TClient
不包含 noHttpClient
作为构造函数依赖项的 a 是没有意义的,所以这也应该被阻止。
这意味着微软堆栈还有改进的空间;-)
推荐阅读
- excel - 检查单元格的百分比格式
- reactjs - React App S3 托管,Url 参数在 S3 上不起作用
- python-3.x - NameError:名称'DatabaseManage'未在python中定义
- php - 在laravel的foreach循环中迭代元素
- latex - tcolorbox 与 tabular、tabularx 兼容吗?
- laravel - 部署中的 Laravel 和 vue js
- linux - 如何使用 awk 从多个文件中搜索字符串?
- python - PYTHON Pandas:在两个数据框中用字符串求和
- sql - 缺少的括号在哪里?
- recursion - 有人能解释一下这个递归吗?谢谢