我今天更新了一个项目到ASP.NET Core 2,我收到以下错误:
不能从singleton IActiveUsersService使用作用域服务IMongoDbContext
我有以下注册:
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)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
为什么DI无法使用该服务?一切都适用于ASP.NET Core 1.1.
juu*_*nas 57
您不能使用寿命较短的服务.仅按请求存在范围服务,而单一服务创建一次并且实例共享.
现在IActiveUsersService
,应用程序中只存在一个实例.但它希望依赖于MongoDbContext
Scoped,并且是按请求创建的.
你必须要么:
MongoDbContext
一个单身人士,或IActiveUsersService
Scoped,或MongoDbContext
作为函数参数传递给用户服务Tob*_*s J 15
Scoped和Singleton服务之间存在重要差异.警告是为了使其发光,关闭它或不加选择地切换寿命以使其消失将无法解决问题.
范围内的服务是通过创建的IServiceScope
.其最重要的目的之一是确保IDisposable
在范围本身时正确处理在该范围内创建的任何服务.
在ASP.NET Core中,会在每个传入请求中自动为您创建服务范围,因此您通常不必担心这一点.但是,您也可以创建自己的服务范围; 你只需要自己处理它.
一种方法是:
IDisposable
,IServiceProvider
,IServiceScope
使用IServiceProvider.CreateScope()
扩展方法创建和存储范围,Dispose
方法中配置服务范围.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 ActiveUsersService: IActiveUsersService, IDisposable
{
private readonly IServiceScope _scope;
public ActiveUsersService(IServiceProvider services)
{
_scope = services.CreateScope(); // CreateScope is in Microsoft.Extensions.DependencyInjection
}
public IEnumerable<Foo> GetFooData()
{
using (var context = _scope.ServiceProvider.GetRequiredService<IMongoDbContext>())
{
return context.GetCollection<Foo>();
}
}
public void Dispose()
{
_scope?.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
根据您使用这些以及您正在使用的作用域服务的方式,您可以改为执行以下操作之一:
IServiceProvider
使用它IServiceScope
在using
块内部创建一个新的,并在块退出时让范围被释放.请记住,当范围本身发生时,IDisposable
从一个IServiceScope
意志创建的任何服务都会自动处理.
简而言之,不要只是改变服务的生命周期来"让它工作"; 你还需要考虑那些并确保它们得到妥善处理.ASP.NET Core自动处理最常见的情况; 对于其他人来说,你只需要做更多的工作.
自从C#1.0以来,我们已经有了using()
块来确保正确处理资源.但是using()
当其他东西(DI服务)为您创建这些资源时,块不起作用.这就是Scoped服务的用武之地,错误地使用它们会导致程序中的资源泄漏.
还有另一种方法可以解决这个问题,它将添加MongoDbContext
到 DI 中,AddTransient
如下所示:
services.AddSingleton<IActiveUsersService, ActiveUsersService>();\nservices.AddTransient<IMongoDbContext, MongoDbContext>();\n
Run Code Online (Sandbox Code Playgroud)\n\n使用这种方法的意义在于,对于使用它的MongoDbContext
每个类,您最终都会得到一个实例。\n例如,如果您有 10 个使用它的 Singleton 类,那么您将拥有它的 10 个实例,但它\而不是为每个请求创建一个实例。Singleton
MongoDbContext
请参阅此参考:Cannot Consume Scoped Service From Singleton \xe2\x80\x93 A Lesson In ASP.net Core DI Scopes
\n您也可以添加
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
Run Code Online (Sandbox Code Playgroud)
.Build()
在Program.cs
文件之前禁用验证。
仅在进行开发测试时尝试使用此方法,ActiveUsersService是单例的,并且其生存期大于MongoDbContext的生存期,该MongoDbContext是有作用域的,不会被废弃。
归档时间: |
|
查看次数: |
25640 次 |
最近记录: |