我有一个需要服务的控制器,所以我将其注入。该服务需要一个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();
实例或注入实例的区别。
答案 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
}