У меня есть приложение ASP.NET MVC 5, которое использует LightInject в качестве контейнера DI, и у меня есть класс Service, который находится в другой библиотеке классов в моем решении VS.
My Solution
|____ASP.NET MVC Web App (async controller calls service method)
|____Service Class Library
|____InMemoryCacheService (Singleton)
Этот класс обслуживания относится к классу Singleton InMemoryCacheService, который я создал в соответствии с подходом Предпочтительный шаблон синглтона Джона Скита (упрощенная версия):
public sealed class InMemoryCacheService
{
private static readonly InMemoryCacheService _singleton = new InMemoryCacheService();
// A private constructor to restrict the object creation from outside
static InMemoryCacheService()
{
}
private InMemoryCacheService()
{
Log.Info("New In Memory Cache Service instance created!");
}
public static InMemoryCacheService Instance
{
get
{
return _singleton;
}
}
public Dictionary<string, ConcurrentDictionary<string, Changeset>> ChangesetCacheDictionary
{
get { return _changesetCacheDictionary; }
set { _changesetCacheDictionary = value; }
}
public string GetChangesetCacheKey(string releaseWorkItemId)
{
return $"{releaseWorkItemId}_{CHANGESET_CACHE}";
}
public T GetOrSet<T>(string cacheKey, TimeSpan duration) where T : class
{
var item = MemoryCache.Default.Get(cacheKey) as T;
if (item == null)
{
lock (CacheLockObject)
{
item = GetItemFromCacheType<T>(cacheKey);
MemoryCache.Default.Add(cacheKey, item, DateTime.Now.Add(duration));
}
}
return item;
}
private T GetItemFromCacheType<T>(string cacheKey) where T : class
{
T result = null;
var tokens = cacheKey.Split('_');
var releaseWorkItemId = tokens[0];
var cacheType = tokens[1];
switch (cacheType)
{
case CHANGESET_CACHE:
result = GetChangesetitItem<T>(releaseWorkItemId);
break;
}
return result;
}
private T GetChangesetitItem<T>(string releaseWorkItemId) where T : class
{
T result = null;
if (ChangesetCacheDictionary == null)
{
ChangesetCacheDictionary = new Dictionary<string, ConcurrentDictionary<string, Changeset>>()
{
{ releaseWorkItemId,new ConcurrentDictionary<string, Changeset>() }
};
}
else if (!ChangesetCacheDictionary.ContainsKey(releaseWorkItemId))
{
ChangesetCacheDictionary.Add(releaseWorkItemId, new ConcurrentDictionary<string, Changeset>());
}
result = ChangesetCacheDictionary[releaseWorkItemId] as T;
return result;
}
}
Проблема в том, что при отладке я заметил, что создается несколько экземпляров моего класса Singleton! На мой одноэлементный экземпляр ссылается метод async Controller для создания отчета, который вызывает мою службу, а служба использует асинхронные задачи Singleton in Parallel.
В первый раз, когда я запускаю свой отчет, он инициализирует синглтон и заполняет кеш, как и ожидалось. Но второй или третий раз, когда я запускаю отчет, создается новый экземпляр. Кажется, этого не происходит, когда я запускаю свое веб-приложение на своем ноутбуке, я вижу его только на своем сервере песочницы. Есть идеи, что может быть не так? Насколько я понимаю, мой синглтон будет создан только один раз.
Вот пример того, как моя служба использует Singleton InMemoryCacheService:
GitCommitCache = InMemoryCacheService.Instance.GetOrSet<ConcurrentDictionary<string,GitCommit>>(gitCommitCacheKey,new TimeSpan(1, 0, 0, 0));
Что заставляет вас думать, что он создается несколько раз? Код выше выглядит нормально.
@DavidG, как вы можете видеть в конструкторе Singleton, я добавил сообщение журнала. Когда я запускаю свой отчет два или три раза, я вижу сообщение о том, что был создан другой экземпляр, и я вижу его, потому что мои кэшированные данные очищены
@Backs Я добавил упрощенную версию моего класса InMemoryCacheService в свой исходный пост
Ваше приложение MVC перезапускается / перерабатывается?
@DavidG Я не вижу перезапуска / перезапуска пула приложений в средстве просмотра событий на сервере для моего пула приложений за последние часы, когда возникла моя проблема.
боже, InMemoryCacheService действительно слишком сложный
@Backs Без кеширования мой отчет занимает 35 минут, постоянно вызывая сервер TFS. Мне нужно было кешировать сложные объекты. Если у вас есть другие предложения, я все слышу.
Я не большой поклонник синглтонов, предпочитаю позволить контейнеру DI обрабатывать все это за меня, это возможность для вас? Вы пользуетесь чем-то вроде Autofac?
На самом деле мой первоначальный подход заключался в настройке моей службы с использованием LightInject с PerContainerLifetime, но с теми же результатами ... Создано несколько экземпляров





Что такое
InMemoryCacheServiceи как он работает?