首页 > 解决方案 > 为什么我不能在需要相同上下文的控制器中注入需要 httpclient 和 EF 上下文的服务

问题描述

我有一个需要服务的控制器,所以我注入它。该服务需要一个HttpClient所以我注入它。它们都需要 EF 上下文。

我确实HttpClient为该服务添加了 at Startup 。但是我有以下错误。

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>创建的实例的T生命周期与HttpClientaspnet 核心创建和管理的生命周期相同DbContext,该生命周期比实际请求的生命周期长。很公平。那么如何将一个注入HttpClient到临时服务中呢?

更新2

根据该博客,我可以注入 in 的一个实例,IHttpClientFactoryMyService不是使用services.AddHttpClient();. 确实,错误消失了。我将不得不做一些阅读以了解向工厂询问实例HttpClient或注入实例之间的区别。

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

解决方案


注册MyService为范围:

services.AddScoped<IMyService, MyService>();

然后,只需注册您HttpClientMyService

services.AddHttpClient<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
}

推荐阅读