Я вижу два общих решения:
- Переместите кеш, которым
DataCache
управляет из этого класса, таким образом, что MyCacheClass
может стать Scoped
.Это кажется легким делом, поскольку это, вероятно, то, для чего MemoryCache
.Кэш памяти, скорее всего, является Singleton. - Переместите
DataCache
в Корень композиции , чтобы он мог безопасно зависеть от контейнера (или абстракции контейнера), не попадая в Service Locatoranti-pattern trap.
Первое решение может быть применено несколькими способами.Возможно, это вопрос определения кэша в поле static
:
public class DataCache
{
private static ConcurrentDictionary<string, object> cache;
}
И в случае, если вы введете MemoryCache
в качестве поставщика хранилища для ваших данных, он будет содержать кэш и образ жизни DataCache
становится неактуальным:
public class DataCache
{
public DataCache(MyContext context, IMemoryCache cache)
}
Если, однако, DataCache
необходимо вводить потребителям синглтона, он сам должен быть синглтоном.Это запрещает этот подход, так как MyContext
необходимо определить, чтобы предотвратить зависимых зависимостей .Для этого вы можете использовать решение 2.
Используя решение, вы гарантируете, что DataCache
создается внутри вашего Корня композиции .Это заставляет вас прятаться 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;
}
}
}
}