C# 为什么可以';在需要相同上下文的控制器中注入一个需要httpclient和EF上下文的服务
我有一个需要服务的控制器,所以我注入了它。该服务需要一个C# 为什么可以';在需要相同上下文的控制器中注入一个需要httpclient和EF上下文的服务,c#,asp.net-core,entity-framework-core,C#,Asp.net Core,Entity Framework Core,我有一个需要服务的控制器,所以我注入了它。该服务需要一个HttpClient,所以我注入了它。它们都需要EF上下文 我确实在服务启动时添加了HttpClient。然而,我有下面的错误 在启动中: services.AddHttpClient<IMyService, MyService>(); 在我的控制器中: private readonly IMyService _myService; public MyController(ReadContext ctx, IMyService
HttpClient
,所以我注入了它。它们都需要EF上下文
我确实在服务启动时添加了HttpClient
。然而,我有下面的错误
在启动中
:
services.AddHttpClient<IMyService, MyService>();
在我的控制器中:
private readonly IMyService _myService;
public MyController(ReadContext ctx, IMyService myService)
{
_ctx = ctx;
_myService = myService;
}
错误:
System.InvalidOperationException:无法从根提供程序解析作用域服务“MyApp.Backend.ReadContext”。
位于Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(类型serviceType、IServiceScope范围、IServiceScope根范围)
位于Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngeCallback.OnResolve(类型serviceType,IServiceScope范围)
在Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(输入serviceType,ServiceProviderEngineScope ServiceProviderEngineScope)
位于Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(类型serviceType)
位于Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp,类型类型,类型requiredBy,布尔值isDefaultParameterRequired)
在lambda_方法中(闭包、IServiceProvider、对象[])
在Microsoft.Extensions.Http.DefaultTypedHttpClientFactory`1.CreateClient(HttpClient HttpClient)
并不是说,当服务被注入到不需要ReadContext
的控制器中时,这是有效的。这里似乎有一些分辨率循环
更新
从评论中,我了解到AddHttpClient
创建了一个T
的实例,其生存期与aspnet core创建和管理的HttpClient
的生存期相同,比实际请求的生存期DbContext
的生存期长。很公平。那么如何将HttpClient
注入到临时服务中呢
更新2
因此,我可以在
MyService
中插入IHttpClientFactory
的实例,而不是使用services.AddHttpClient()代码>。事实上,错误消失了。我必须做一些阅读,以理解向工厂索要HttpClient
实例与注入实例之间的区别。按范围注册MyService
:
services.AddScoped<IMyService, MyService>();
按照您现在的做法,MyService
是在单例范围内创建的,这使得不可能像您的上下文那样注入范围依赖项
或者,您可以插入IServiceProvider,并使用服务定位器反模式获取上下文。它被称为反模式是有原因的,所以这不是最好的方式,但是如果您的服务是单例范围的,那么没有其他方式:
public class MyService : IMyService
{
private readonly HttpClient _client;
private readonly IServiceProvider _services;
public MyService(HttpClient client, IServiceProvider services)
{
_client = client;
_services = services;
}
}
然后,稍后:
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ReadContext>();
// do something
}
使用(var scope=\u services.CreateScope())
{
var context=scope.ServiceProvider.GetRequiredService();
//做点什么
}
错误信息应该非常清楚MyService
在应用程序范围内从根容器解析,而DbContext注册为作用域服务,并由作用域容器解析(在每次请求时创建)。如果将MyService
注入到HttpClient中,除非应用程序关闭,否则它基本上会成为作用域(并且永远不会被释放),从而导致DbContext资源(EF核心缓存、跟踪等)出现内存泄漏永远不会免费我只是想在整个应用程序中使用一个“单一”HttpClient
(我让aspnetcore处理最好的方式)时,让MyController
和MyService成为暂时的。我该怎么办?我遵循了您将MyService作为HttpClient注入的示例,HttpClient将是一个单例,因此它不能依赖于作用域服务,即DbContext,DbContext永远不应该是单例,因此,您应该删除该构造函数依赖项,而是将dbcontext传递给HttpClientI上的方法。我希望文档提到,通过AddHttpClient
链接IMyService
和MyService
将MyService
变成了一个单例。很明显,这是事后诸葛亮。那么我如何将HttpClient注入到一个临时服务中呢?将静态对象注入到作用域对象或瞬态对象中没有问题,当作用域对象/瞬态对象被释放时,它们不会被释放。但是将瞬态/作用域服务注入到单例中是一个问题,因为单例的生存期等于应用程序(或传统.NET Framework中的AppDomain,而不是.NET Core)TK的生存期。我会尽快试一试。顺便说一句,我从不做服务定位器,我不知道你为什么在回答中提到它。它不起作用。这就像在任何类型上使用AddHttpClient
创建要注入的该类型的单例一样。它是IServiceProvider
,而不是IServiceCollection
^^
public class MyService : IMyService
{
private readonly HttpClient _client;
private readonly IServiceProvider _services;
public MyService(HttpClient client, IServiceProvider services)
{
_client = client;
_services = services;
}
}
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ReadContext>();
// do something
}