public async Task <TData> GetAsync <TData>(CacheContentType type, string parameter = null) { await _cacheLock.WaitAsync(); try { if (!_dataProviders.TryGetValue(type, out var dataProvider)) { throw new NoDataProviderException($"{type} data provider doesn't exist in cache."); } if (!_items.ContainsKey(new Tuple <CacheContentType, string>(type, parameter))) { var data = await FetchDataFromProvider(dataProvider, parameter, null); _items.TryAdd(new Tuple <CacheContentType, string>(type, parameter), new CacheItem(data)); _cacheItemsAdded++; _logger.Info($"Cache data added ({type})"); ApplyPatches(type, data); return((TData)data); } var cachedItem = _items[new Tuple <CacheContentType, string>(type, parameter)]; var lifetimeAttribute = type.GetEnumMemberAttribute <CacheLifetimeAttribute>(type); if ((DateTime.Now - cachedItem.UpdateTime).TotalMinutes >= lifetimeAttribute.Lifetime) { var data = await FetchDataFromProvider(dataProvider, parameter, cachedItem.Data); if (data != cachedItem.Data) { ApplyPatches(type, data); cachedItem.Update(data); _logger.Info($"Cache data updated ({type})"); } _cacheItemsUpdated++; } else { _cacheItemsHit++; } return((TData)cachedItem.Data); } finally { _cacheLock.Release(); } }