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 2.0后,无法使用singleton IActiveUserService中的作用域服务IMongodContext_C#_Asp.net Core - Fatal编程技术网

C# 升级到ASP.NET Core 2.0后,无法使用singleton IActiveUserService中的作用域服务IMongodContext

C# 升级到ASP.NET Core 2.0后,无法使用singleton IActiveUserService中的作用域服务IMongodContext,c#,asp.net-core,C#,Asp.net Core,我今天将一个项目更新为ASP.NET Core 2,出现以下错误: 无法从singleton IActiveUserService使用作用域服务IMongodContext 我有以下注册: services.AddSingleton<IActiveUsersService, ActiveUsersService>(); services.AddScoped<IMongoDbContext, MongoDbContext>(); services.AddSingleton(

我今天将一个项目更新为ASP.NET Core 2,出现以下错误:

无法从singleton IActiveUserService使用作用域服务IMongodContext

我有以下注册:

services.AddSingleton<IActiveUsersService, ActiveUsersService>();
services.AddScoped<IMongoDbContext, MongoDbContext>();
services.AddSingleton(option =>
{
   var client = new MongoClient(MongoConnectionString.Settings);
   return client.GetDatabase(MongoConnectionString.Database);
})



public class MongoDbContext : IMongoDbContext
{
   private readonly IMongoDatabase _database;

   public MongoDbContext(IMongoDatabase database)
   {
      _database = database;
   }

   public IMongoCollection<T> GetCollection<T>() where T : Entity, new()
   {
      return _database.GetCollection<T>(new T().CollectionName);
   }
}

public class IActiveUsersService: ActiveUsersService
{

   public IActiveUsersService(IMongoDbContext mongoDbContext)
   {
      ...
   }
}
services.AddSingleton();
services.addScope();
services.AddSingleton(选项=>
{
var client=newmongoclient(MongoConnectionString.Settings);
返回client.GetDatabase(MongoConnectionString.Database);
})
公共类MongoDbContext:IMongoDbContext
{
私有只读IMongoDatabase_数据库;
公共MongoDbContext(IMongoDatabase数据库)
{
_数据库=数据库;
}
公共IMongoCollection GetCollection(),其中T:Entity,new()
{
返回_database.GetCollection(新的T().CollectionName);
}
}
公共类IActiveUsersService:ActiveUsersService
{
公共IActiveUserService(IMongoDbContext mongoDbContext)
{
...
}
}

为什么DI不能使用该服务?所有这些都适用于ASP.NET Core 1.1。

您不能使用寿命更短的服务。作用域服务只存在于每个请求中,而单例服务只创建一次,实例是共享的

现在应用程序中只存在一个
iactiveUserService
实例。但它需要依赖于
MongoDbContext
,它的作用域是限定的,并且是根据请求创建的

您必须:

  • MongoDbContext
    设置为单例,或
  • 使
    IActiveUserService
    范围化,或
  • MongoDbContext
    作为函数参数传递到用户服务中
  • 您还可以添加

    .UseDefaultServiceProvider(options =>
                        options.ValidateScopes = false)
    
    Program.cs
    文件中的
    .Build()
    之前禁用验证


    请仅在开发测试时尝试此方法,ActiveUsersService是单例服务,其生存期比MongoDbContext的生存期长,MongoDbContext受范围限制且不会被处理。

    范围限制服务和单例服务之间存在重要区别。警告就是为了揭示这一点,不分青红皂白地关掉它或在一生中不分青红皂白地切换它,让它消失,并不能解决问题

    作用域服务是从
    IServiceScope
    创建的。其最重要的目的之一是确保在该作用域中创建的任何
    IDisposable
    服务在作用域本身运行时都得到正确处理

    在ASP.NETCore中,每个传入请求都会自动为您创建一个服务范围,因此您通常不必担心这一点。但是,您也可以创建自己的服务范围;你只需要自己处理它

    一种方法是:

    • 使您的单件服务
      IDisposable
    • 注入IServiceProvider
    • 使用扩展方法创建并存储
      IServiceScope
      范围
    • 使用该作用域创建所需的作用域服务
    • 使用
      dispose
      方法处置服务范围
    services.AddSingleton();
    services.addScope();
    services.AddSingleton(选项=>
    {
    var client=newmongoclient(MongoConnectionString.Settings);
    返回client.GetDatabase(MongoConnectionString.Database);
    })
    公共类MongoDbContext:IMongoDbContext
    {
    私有只读IMongoDatabase_数据库;
    公共MongoDbContext(IMongoDatabase数据库)
    {
    _数据库=数据库;
    }
    公共IMongoCollection GetCollection(),其中T:Entity,new()
    {
    返回_database.GetCollection(新的T().CollectionName);
    }
    }
    公共类ActiveUsersService:IActiveUserService,IDisposable
    {
    专用只读iSeries示波器_范围;
    公共活动用户服务(IServiceProvider服务)
    {
    _scope=services.CreateScope();//CreateScope位于Microsoft.Extensions.DependencyInjection中
    }
    公共IEnumerable GetFooData()
    {
    使用(var context=\u scope.ServiceProvider.GetRequiredService())
    {
    返回context.GetCollection();
    }
    }
    公共空间处置()
    {
    _范围?.Dispose();
    }
    }
    
    根据您使用这些服务的方式以及使用的范围服务,您可以执行以下操作之一:

    • 创建作用域服务的单个实例,并在单例生命周期中使用它;或
    • 每次需要作用域服务时,存储对(注入的)根
      IServiceProvider
      的引用,使用它在
      using
      块内创建一个新的
      IServiceScope
      ,并在该块退出时释放该作用域
    请记住,从
    IServiceScope
    创建的任何
    IDisposable
    服务都将在作用域本身发生故障时自动处理

    简而言之,不要只是改变服务的生命周期来“让它工作”;你仍然需要考虑这些问题,并确保它们得到妥善处理。ASP.NET Core自动处理最常见的案例;对于其他人来说,你只需要做更多的工作


    从C#1.0开始,我们就有了
    使用()
    块来确保正确地分配资源。但是当其他东西(DI服务)正在为您创建这些资源时,
    using()
    块不起作用。这就是作用域服务的用武之地,不正确地使用它们将导致程序中的资源泄漏。

    还有另一种解决此问题的方法,就是将
    MongoDbContext
    作为
    AddTransient
    添加到DI中,如下所示:

    services.AddSingleton<IActiveUsersService, ActiveUsersService>();
    services.AddTransient<IMongoDbContext, MongoDbContext>();
    
    services.AddSingleton();
    services.AddTransient();
    
    使用这种方法的意义在于,对于使用它的每个
    Singleton
    类,您最终都会得到一个
    MongoDbContext
    实例。 例如,如果您有10个使用
    MongoDbContext
    的单例类,那么您将有10个实例,但它不是为每个请求创建一个实例

    看到这个了吗
    services.AddSingleton<IActiveUsersService, ActiveUsersService>();
    services.AddTransient<IMongoDbContext, MongoDbContext>();