使缓存的数据和依赖项注入模式无效

问题描述 投票:1回答:2

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

此类的基本功能是缓存参考数据。为了获得此参考数据,它需要一个Entity Framework dbContext实例。这通过依赖项注入(简单注入器)传递。

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

缓存每2小时失效一次,然后重新查询。毫不奇怪,届时dbContext已被清理(因为它超出了范围)。

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

任何人都知道在类中经常需要注入的设计模式吗?

多一点背景:

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

using (AsyncScopedLifestyle.BeginScope(container))
{
    // Setup the long lived data caching
    var dataCache = container.GetInstance<DataCache>();
    dataCache.SetupCachedItems();
}
  • 它设置MemoryCache使两个小时后的缓存中的数据过期。但是到那时,注入的上下文早已清理干净。
asp.net-core dependency-injection .net-core simple-injector
2个回答
2
投票

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

  1. DataCache管理的缓存移出该类,以使MyCacheClass可以成为Scoped。这毫无疑问,因为这很可能是MemoryCache的目的。内存缓存可能是单例。
  2. DataCache移至Composition Root,以便它可以安全地依赖于容器(或容器抽象),而不会陷入Service Locator anti-pattern陷阱中。

第一种解决方案可以多种方式应用。也许是在static字段中定义缓存的问题:

public class DataCache
{
    private static ConcurrentDictionary<string, object> cache;
}

并且如果您将MemoryCache作为数据的存储提供者注入,它将包含缓存,并且DataCache的生活方式将变得无关紧要:

public class DataCache
{
    public DataCache(MyContext context, IMemoryCache cache)
}

但是,如果需要将DataCache注入Singleton使用者,则它本身必须是Singleton。由于MyContext需要确定范围,因此无法使用此方法来防止Captive Dependencies。为此,您可以使用解决方案2。

使用解决方案,请确保在DataCache内部创建了Composition Root。这会迫使您将DataCache隐藏在抽象后面,例如IDataCache。可以将这种抽象放置在允许消费者依赖的位置,而DataCache实现将完全隐藏在“合成根”内部。在那个位置依靠DI容器变得安全。

// Part of the Composition Root
sealed class DataCache: IDataCache
{
    public DataCache(Container container, IMemoryCache cache) ...

    public ProductData GetProductByKey(string key)
    {
        if (key not in cache)
        {
            using (AsyncScopedLifestyle.BeginScope(this.container))
            {
                var context = container.GetInstance<MyContext>();
                var p = context.Products.SingleOrDefault(p => p.Key == key);
                var data = new ProductData(p);
                AddProductToCache(key, data);
                return data;
            }
        }
    }
}

-1
投票

您应该完全依赖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
}

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

© www.soinside.com 2019 - 2024. All rights reserved.