Asp.net core 使缓存数据和依赖项注入模式无效

Asp.net core 使缓存数据和依赖项注入模式无效,asp.net-core,dependency-injection,.net-core,simple-injector,Asp.net Core,Dependency Injection,.net Core,Simple Injector,我有一个数据缓存类(使用MemoryCache类) 此类的基本功能是缓存引用数据。要获取此引用数据,它需要实体框架dbContext的实例。这是通过依赖项注入(简单注入器)传入的 但是这个dbContext的生命周期是“每次调用”(AsyncScopedLifestyle)。因此,为了满足这一点,我将设置缓存的调用放在一个“作用域”中,该“作用域”在调用后过期 缓存每2小时失效一次,并重新查询。毫不奇怪,dbContext到那时已经清理完毕(因为它超出了范围) 我可以想办法绕过这个问题。但我想知

我有一个数据缓存类(使用
MemoryCache
类)

此类的基本功能是缓存引用数据。要获取此引用数据,它需要实体框架dbContext的实例。这是通过依赖项注入(简单注入器)传入的

但是这个dbContext的生命周期是“每次调用”(
AsyncScopedLifestyle
)。因此,为了满足这一点,我将设置缓存的调用放在一个“作用域”中,该“作用域”在调用后过期

缓存每2小时失效一次,并重新查询。毫不奇怪,dbContext到那时已经清理完毕(因为它超出了范围)

我可以想办法绕过这个问题。但我想知道,对于这类问题,我是否应该遵循一种模式。(我的大多数解决方案都让我将容器传递到缓存类中。但这似乎违反了几个DI模式。)

有人知道在类内部重复需要注入时要使用的设计模式吗?

更多的背景:

  • 我的缓存类(称为
    DataCache
    )从构造函数注入中获取上下文
  • 通过Startup.cs中的Configure方法进行设置调用。这看起来像这样:

使用(AsyncScopedLifestyle.BeginScope(容器))
{
//设置长期数据缓存
var dataCache=container.GetInstance();
SetupCachedItems();
}
  • 它将MemoryCache设置为在两小时后使缓存中的数据过期。但到那时,注入的上下文早已清理干净

    • 您应该全程依赖DI。换句话说,如果缓存类需要上下文,那么这是一个依赖项,应该这样注入:

      public class MyCacheClass
      {
          private readonly MyContext _context;
      
          public MyCacheClass(MyContext context)
          {
              _context = context;
          }
      
          ...
      }
      
      当然,这是假设缓存类也有一个作用域生存期,实际上没有理由不这样做,因为它与作用域依赖项交互。但是,如果出于某种原因需要它具有单例生存期,则可以简单地插入
      IServiceProvider
      ,然后创建一个作用域并在需要时拉出上下文:

      using (var scope = _serviceProvider.CreateScope())
      {
          var context = scope.ServiceProvider.GetRequiredService<MyContext>();
          // do something with context
      }
      
      使用(var scope=\u serviceProvider.CreateScope())
      {
      var context=scope.ServiceProvider.GetRequiredService();
      //根据上下文做一些事情
      }
      

      如果您使用的是静态类,请不要这样做。

      我在这里看到两种通用解决方案:

    • DataCache
      管理的缓存移出该类,这样
      MyCacheClass
      可以成为
      范围
      。这很容易理解,因为这可能就是
      MemoryCache
      的用途。内存缓存很可能是单例的
    • DataCache
      移动到中,这样它就可以安全地依赖于容器(或容器抽象),而不会落入陷阱
    • 第一种解决方案可以以多种方式应用。可能是在
      静态
      字段中定义缓存的问题:

      公共类数据缓存
      {
      私有静态ConcurrentDictionary缓存;
      }
      
      如果您将
      MemoryCache
      作为数据的存储提供程序注入,它将包含缓存,
      DataCache
      的生活方式将变得无关紧要:

      公共类数据缓存
      {
      公共数据缓存(MyContext上下文,IMemoryCache缓存)
      }
      
      但是,如果需要将
      DataCache
      注入到单例消费者中,那么它本身就需要是单例的。这不允许使用这种方法,因为需要对MyContext的范围进行限定,以防止出现错误。为此,您可以使用解决方案2

      使用解决方案,您可以确保在您的内部创建
      数据缓存。这迫使您将
      DataCache
      隐藏在抽象后面,例如
      IDataCache
      。这个抽象可以放在一个允许使用者依赖的位置,而
      DataCache
      实现将完全隐藏在合成根中。在该位置,依赖DI容器变得安全

      //组成根目录的一部分
      密封类数据缓存:IDataCache
      {
      公共数据缓存(容器容器,IMemoryCache缓存)。。。
      public ProductData GetProductByKey(字符串键)
      {
      如果(密钥不在缓存中)
      {
      使用(AsyncScopedLifestyle.BeginScope(this.container))
      {
      var context=container.GetInstance();
      var p=context.Products.SingleOrDefault(p=>p.Key==Key);
      var数据=新产品数据(p);
      AddProductToCache(键、数据);
      返回数据;
      }
      }
      }
      }
      
      数据缓存类是什么样子的?它从何处获得上下文以及如何获得上下文?在任何情况下,它都应该仅在需要加载新数据时请求上下文。当这种情况发生时,它需要创建一个作用域来获取每次调用的上下文。问题与此类似。能否使用通过在后台定期刷新缓存的
      AddHostedService
      设置的
      BackgroundService
      ?DBContext可以被注入到
      后台服务中
      ,因此在单个请求的范围之外可用。尽管答案写得很好,但很抱歉对您投了否决票。我真的不喜欢这里使用服务定位器。服务定位器是反模式的,因为总有更好的解决方案。尽管asp.net内核被标记了,但这个问题与IServiceProvider并没有真正的关系。这不是反对票的目的。而且,当你有一个单例类,这是你唯一的选择。没有更好的选择了。正如我在回答中所说的,最好使用作用域生存期。也是这样,因为无论您使用什么DI容器,它仍然使用Microsoft.Extensions.DependencyInjection facades。我的缓存在单实例生存期内运行。因为它只是挂在周围试图阻止较慢的呼叫。如果它被重新创建
      using (var scope = _serviceProvider.CreateScope())
      {
          var context = scope.ServiceProvider.GetRequiredService<MyContext>();
          // do something with context
      }