Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无法在存储库构造函数asp.net core中创建服务范围_C#_Asp.net Core_Dependency Injection_Repository Pattern - Fatal编程技术网

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。这应该和为模式而设计模式一样重要,如果不是更多的话。“单身的一切”只是一个稻草人。明智的权衡总是必要的。但是,“范围一切”肯定不是最好的方法。如果你认为我错了,我会让你给我一个你在生产中以这种方式编写的代码的剖析器,我会立即在你的生产代码中向你展示你的建议的效果。更多细节请给我留言。谢谢你,杰夫