C# 升级到ASP.NET Core 2.0后,无法使用singleton IActiveUserService中的作用域服务IMongodContext
我今天将一个项目更新为ASP.NET Core 2,出现以下错误: 无法从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(
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>();