【发布时间】:2021-09-14 16:13:20
【问题描述】:
我正在尝试创建依赖于IMemoryCache 的Singleton CacheManager 类。
public class CacheManager:ICacheManager
{
private readonly IMemoryCache _cache;
public CacheManager(IMemoryCache cache)
{
_cache = cache;
}
public void LoadCache(MyData data)
{
// load cache here at startup from DB
}
}
我还有一个Scoped 服务,可以从数据库中检索数据
public class LookupService:ILookupService
{
private readonly MyDatabaseContext _dbContext;
public class LookupService(MyDatabaseContext dbContext)
{
_dbContext = dbContext;
}
public void Dispose()
{
//Dispose DBContext here
}
// some async methods that returns lookup collection
}
在 Startup.cs 中注册这些服务
public void ConfigureServices(IServiceCollection services)
{
// EF
services.AddDbContext<MyDatabaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// domain services
services.AddScoped<ILookupService, LookupService>();
services.AddMemoryCache();
// singleton
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var service = scope.ServiceProvider.GetService<ILookupService>())
{
how do i create cacheManager instance by injecting IMemoryCache and also register callback function
}
}
});
}
ILookupService 注册为Scoped 服务,因为它依赖于 DBContext,DBContext 也(默认情况下)注册Scoped 生命周期。我不想更改这些服务的生命周期。
但是我希望将 CacheManager 注册为 Singleton,这意味着我不能将 ILookupService 作为依赖项注入到 CacheManager 中。
所以这是我创建和注册 CacheManager 单例实例的可能解决方案
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var lookupService = scope.ServiceProvider.GetService<ILookupService>())
{
var cache = scope.ServiceProvider.GetService<IMemoryCache>();
var manger = new CacheManager(cache);
manger.LoadCache(lookupService.GetData());
return manger;
}
}
});
不确定这是创建 CacheManager 的最佳方式。如果 CacheEntry 变为 null,如何实现回调函数重新填充?
【问题讨论】:
-
你的最后一个块码寄存器还能用吗? AFAIK,它只是从单独的范围创建
CacheManager的单例实例,将返回DbContext的独立实例,但DbContext现在也将成为单例。只要您继续使用它,这应该会导致范围过程和更改跟踪的各种问题(我个人认为它应该在部署后一段时间后抛出许多异常) -
为什么会返回单例 DBContext?
scope.ServiceProvider.GetService<ILookupService>()行应该返回作用域实例。默认情况下,在 Web App 中,EF 将注册 DBContext 的作用域实例 -
工厂方法在
CacheManager实例初始化时只调用了一次,因此只创建了一个lookupService实例来帮助CacheManager第一次加载数据。那么这里有什么区别呢?或者,如果您从一开始就打算将lookupService用于CacheManager的初始数据,那么它应该没问题。我虽然CacheManager使用ILookupService作为依赖项。我可能已经错过了一些东西 -
是的,查找服务用于在应用程序启动时将数据从数据库加载到缓存中。我们不能在 CacheManager 中注入 ILookupService 作为依赖项。 DI 框架将抛出错误为
Singleton Cannot consume scoped service。我想知道CacheManager是否是Singleton,当它变为null时重新填充CacheEntry的正确方法是什么 -
长寿命服务通过 DI 访问短寿命服务的常用方法是注入一个根据需要创建短寿命服务的工厂。在你的情况下这是不可能的吗?
标签: asp.net-core asp.net-core-mvc asp.net-core-5.0 memorycache