C# 无法在存储库构造函数asp.net core中创建服务范围
我有临时存储库服务,每次调用它时都需要创建服务范围 我尝试在存储库构造函数中创建此作用域,如下所示:C# 无法在存储库构造函数asp.net core中创建服务范围,c#,asp.net-core,dependency-injection,repository-pattern,C#,Asp.net Core,Dependency Injection,Repository Pattern,我有临时存储库服务,每次调用它时都需要创建服务范围 我尝试在存储库构造函数中创建此作用域,如下所示: public class ServiceRepository : IServiceRepository { private IServiceScopeFactory _serviceScopeFactory; private IServiceScope _scope; private IServiceProvider _serviceContainer; pri
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;
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options => options.ValidateScopes = false)
.Build();
之后,我尝试从服务提供商处调用我的存储库服务:
var serviceRepository = _serviceProvider.GetRequiredService<IServiceRepository>();
我做错了什么?在此之前,我将作用域设置为这样,并且效果良好:
var scopeFactory = _serviceProvider.GetService<IServiceScopeFactory>();
var scope = scopeFactory.CreateScope();
var scopedContainer = scope.ServiceProvider;
var scopeFactory=\u serviceProvider.GetService();
var scope=scopeFactory.CreateScope();
var scopedContainer=scope.ServiceProvider;
但在这种情况下,我需要在每次调用IServiceRepository之前声明作用域。这就是我想在IServiceRepository构造函数中声明作用域的原因。我帮助我添加
。使用DefaultServiceProvider(options=>options.ValidateScopes=false)
到Program.cs
中的BuildWebHos
t,如下所示:
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;
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseDefaultServiceProvider(options => options.ValidateScopes = false)
.Build();
公共静态IWebHost BuildWebHost(字符串[]args)=>
WebHost.CreateDefaultBuilder(args)
.UseStartup()
.UseDefaultServiceProvider(选项=>options.ValidateScopes=false)
.Build();
我希望它对某些人也有帮助你把这些都用错了。首先,瞬态生存期对象可以直接注入作用域服务。您不应该注入
IServiceProvider
或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
}
使用(var scope=\u provider.CreateScope())
{
var myScopedService=scope.ServiceProvider.GetRequiredService();
//对作用域服务执行某些操作
}
这也是为什么服务定位器是反模式的另一个原因:它会导致大量迟钝和重复的代码。有时候你别无选择,但大多数时候你会这样做。虽然从DI设计的角度来看是完全正确的,但不幸的是,我想我应该补充一点,“性能优化往往会挑战代码抽象”——一旦你看到在Azure生产中执行Gen 0垃圾收集花费了3.8秒,然后开始重新评估分配。即使是短命的,单例也是/应该是特殊用途的,并使用该生命周期创建,因为它们需要该生命周期,即在整个应用程序表面上维护状态。当然,使用scoped可能会带来分配成本,但这在很大程度上是为了降低代码复杂性和熵。如果你的目标是单件处理所有事情,那么你根本不应该使用依赖注入,不管怎样,这将为你带来比GC更高的性能。如何收回3.8秒TTFB的成本?你没有。在各种情况下,这都是销售收入的最大损失,包括:反弹率增加、购物车尺寸减小、购物车被丢弃等等。有很多方法可以重构代码,以便将原本属于范围的DI迁移到Singleton。这应该和为模式而设计模式一样重要,如果不是更多的话。“单身的一切”只是一个稻草人。明智的权衡总是必要的。但是,“范围一切”肯定不是最好的方法。如果你认为我错了,我会让你给我一个你在生产中以这种方式编写的代码的剖析器,我会立即在你的生产代码中向你展示你的建议的效果。更多细节请给我留言。谢谢你,杰夫