c# - 无法在存储库构造函数 asp.net core 中创建服务范围
问题描述
我有临时存储库服务,每次调用它时都需要创建服务范围。
我试图在存储库构造函数中创建这个范围,如下所示:
public class ServiceRepository : IServiceRepository
{
private IServiceScopeFactory _serviceScopeFactory;
private IServiceScope _scope;
private IServiceProvider _serviceContainer;
private DataBaseContext _db;
public ServiceRepository(DataBaseContext context, IServiceScopeFactory serviceScopeFactory)
{
_db = context;
_serviceScopeFactory = serviceScopeFactory;
_scope = _serviceScopeFactory.CreateScope();
_serviceContainer = _scope.ServiceProvider;
}
之后我尝试从服务提供商调用我的存储库服务:
var serviceRepository = _serviceProvider.GetRequiredService<IServiceRepository>();
我希望每次以这种方式调用此服务时,都会创建我在存储库构造函数中声明的服务范围。但是在访问服务时,我得到了错误:
System.InvalidOperationException: 'Cannot resolve 'Data_Access_Layer.Interfaces.IServiceRepository' from root provider because it requires scoped service 'Data_Access_Layer.EF.DataBaseContext'.'
我究竟做错了什么?之前,我已经设置了这样的范围并且它有效:
var scopeFactory = _serviceProvider.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var scopedContainer = scope.ServiceProvider;
但在这种情况下,我需要在每次调用 IServiceRepository 之前声明范围。这就是为什么我想在 IServiceRepository 构造函数中声明范围。
解决方案
你用错了所有这些。首先,瞬态生命周期对象可以直接注入作用域服务。您不应该注入orIServiceProvider
等IServiceScopeFactory
,而是注入您的实际依赖项。您已经直接注入了您的上下文(这是一个范围服务),所以我不确定您为什么要尝试以不同的方式处理任何其他事情。
只有当您的对象具有单例生命周期并且需要范围服务时,您才应该注入IServiceProvider
(仅此而已)。这被称为服务定位器反模式,它之所以成为反模式是有原因的:您应该尽可能避免这样做。一般来说,大多数人认为应该是单例的东西实际上不应该是单例。只有少数情况下您真正需要单例生命周期。在所有其他情况下,“作用域”应该是您的首选生命周期。此外,如果您的单例确实需要范围服务,那么它实际上应该是范围本身的一个强有力的论据。
但是,如果您确实发现自己确实需要单例生命周期并且仍然需要范围服务,那么正确的方法如下:
public class MySingletonService
{
private readonly IServiceProvider _provider;
public MySingletonService(IServiceProvider provider)
{
_provider = provider;
}
...
}
就是这样。您不会在构造函数内创建范围。从范围检索到的任何服务都只存在于该范围内,当范围消失时,服务也将消失。因此,您不能将作用域服务持久化到单例上的 ivar。相反,在需要此类服务的每个单独方法中,您需要执行以下操作:
using (var scope = _provider.CreateScope())
{
var myScopedService = scope.ServiceProvider.GetRequiredService<MyScopedService>();
// do something with scoped service
}
这也是服务定位器是反模式的另一个原因:它会导致大量迟钝和重复的代码。有时你别无选择,但大多数时候你会这样做。
推荐阅读
- javascript - 角度形式的条件要求验证
- python - Why does set() in set() not raise a TypeError, unlike {} in set(), [] in set(), set() in {}, [] in {}, or {} in {}?
- azure - Azure CosmosDb 分区键 - 不同的架构
- javascript - 循环 - 如何在每个循环中添加一个变量
- dependency-injection - c#中的松散耦合
- python - 当用户输入的参数多于函数可以处理的参数时,如何获取与 TypeError 相关的异常
- json - json_query 上的 Ansible 断言
- c# - 如何绑定到集合的项目属性?
- python - 如何访问 youtube 第一搜索结果?
- javascript - 如何在 react-hook-forms 中重置自动完成功能?