edd*_*P23 16 c# .net-core asp.net-core
在我的 Asp.Net Core 应用程序中,我需要一个可以在应用程序的生命周期内重用的单例服务。为了构建它,我需要一个DbContext(来自 EF Core),但它是一个作用域服务并且不是线程安全的。
因此,我使用以下模式来构建我的单例服务。它看起来有点老套,因此我想知道这是否是一种可以接受的方法并且不会导致任何问题?
services.AddScoped<IPersistedConfigurationDbContext, PersistedConfigurationDbContext>();
services.AddSingleton<IPersistedConfigurationService>(s =>
{
ConfigModel currentConfig;
using (var scope = s.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
currentConfig = dbContext.retrieveConfig();
}
return new PersistedConfigurationService(currentConfig);
});
...
public class ConfigModel
{
string configParam { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*att 35
你所做的事情不好,肯定会导致问题。由于这是在服务注册中完成的,因此当您的单例首次注入时,将检索作用域服务一次。换句话说,这里的代码只会在您注册的服务的生命周期内运行一次,因为它是单例,意味着它只会发生一次。此外,您在此处注入的上下文仅存在于您创建的范围内,一旦 using 语句关闭,该范围就会消失。因此,当您实际尝试在单例中使用上下文时,它将已被释放,并且您将获得一个ObjectDisposedException.
如果您需要在单例中使用作用域服务,那么您需要注入IServiceProvider到单例中。然后,您需要创建一个作用域,并在需要使用它时提取上下文,并且每次需要使用它时都需要执行此操作。例如:
public class PersistedConfigurationService : IPersistedConfigurationService
{
private readonly IServiceProvider _serviceProvider;
public PersistedConfigurationService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task Foo()
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<IPersistedConfigurationDbContext>();
// do something with context
}
}
}
Run Code Online (Sandbox Code Playgroud)
再次强调一下,您需要在需要利用作用域服务(您的上下文)的每个方法中执行此操作。你不能将其持久化到 ivar 或其他东西。如果您对代码感到厌烦,那么您应该这样做,因为这是一种反模式。如果您必须在单例中获得范围服务,您别无选择,但通常情况下,这是设计不佳的标志。如果一个服务需要使用作用域服务,那么它几乎总是应该是作用域本身,而不是单例。只有少数情况下,您真正需要单例生命周期,并且这些情况大多围绕着处理信号量或需要在应用程序的整个生命周期中保留的其他状态。除非有充分的理由让您的服务成为单例,否则您应该在所有情况下选择范围;范围应该是默认的生命周期,除非你有理由这样做。
Tan*_*jel 10
尽管ASP.NET Core 中的依赖注入:服务生命周期文档说:
从单例解析范围服务是危险的。它可能会导致服务在处理后续请求时出现不正确的状态。
但就你而言,这不是问题。实际上,您并没有从单例中解析范围服务。它只是在需要时从单例获取作用域服务的实例。所以你的代码应该正常工作,没有任何已处理的上下文错误!
但另一个潜在的解决方案是使用IHostedService. 以下是有关它的详细信息:
| 归档时间: |
|
| 查看次数: |
33826 次 |
| 最近记录: |