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
}