为什么我不能在需要相同上下文的控制器中注入需要httpclient和EF上下文的服务

时间:2018-10-12 13:28:40

标签: c# asp.net-core entity-framework-core

我有一个需要服务的控制器,所以我将其注入。该服务需要一个booklist_clause = f"AND book IN ({booklist})" if booklist else "" strsql = f"SELECT * FROM table WHERE ccy = 'AAA' {booklist_clause}" ,因此我将其注入。他们俩都需要EF上下文。

我确实在启动时为服务添加了HttpClient。但是我有以下错误。

HttpClient中:

Startup

services.AddHttpClient<IMyService, MyService>(); 类中

MyService

在我的控制器中:

private readonly HttpClient _httpClient;
private readonly ReadContext _readContext;
public MyService(HttpClient httpClient, ReadContext readContext)
{
    _httpClient = httpClient;
    _readContext = readContext;
}

错误:

private readonly IMyService _myService;
public MyController(ReadContext ctx, IMyService myService)
{
    _ctx = ctx;
    _myService = myService;
}

并非如此,当将服务注入不需要System.InvalidOperationException: Cannot resolve scoped service 'MyApp.Backend.ReadContext' from root provider. at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired) at lambda_method(Closure , IServiceProvider , Object[] ) at Microsoft.Extensions.Http.DefaultTypedHttpClientFactory`1.CreateClient(HttpClient httpClient) 的控制器中时,此方法有效。这里似乎存在一些解析循环。

更新

从评论中,我了解到ReadContext创建的AddHttpClient<T>实例的寿命与由ASPNET核心创建和管理的T的寿命长于HttpClient生命周期,即实际请求的生命周期。很公平。然后如何将DbContext注入到瞬态服务中?

UPDATE2

根据blog,我可以在HttpClient中插入IHttpClientFactory的实例,而不要使用MyService。确实,错误消失了。我必须做些阅读才能了解向工厂索要services.AddHttpClient();实例或注入实例的区别。

1 个答案:

答案 0 :(得分:0)

MyService注册为范围:

services.AddScoped<IMyService, MyService>();

然后,只需向HttpClient注册MyService

services.AddHttpClient<MyService>();

您现在做的方式是,MyService是在单例作用域中创建的,这使得无法注入像您的上下文这样的作用域依赖性。

或者,您可以改为注入IServiceCollection并使用service-locator反模式来获取上下文。出于某种原因,它被称为反模式,因此这并不是处理问题的最佳方法,但是如果您的服务是单例范围的,则没有其他方法:

public class MyService : IMyService
{
    private readonly HttpClient _client;
    private readonly IServiceCollection _services;

    public MyService(HttpClient client, IServiceCollection services)
    {
        _client = client;
        _services = services;
    }
}

然后,稍后:

using (var scope = _services.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<ReadContext>();
    // do something
}