/// <inheritdoc /> public object Get(string key, Func <object> factory, TimeSpan?timeout, bool isSliding = false, string[] dependentFiles = null) { // see notes in HttpRuntimeAppCache Lazy <object> result; using (var lck = new UpgradeableReadLock(_locker)) { result = MemoryCache.Get(key) as Lazy <object>; if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null { result = SafeLazy.GetSafeLazy(factory); var policy = GetPolicy(timeout, isSliding, dependentFiles); lck.UpgradeToWriteLock(); //NOTE: This does an add or update MemoryCache.Set(key, result, policy); } } //return result.Value; var value = result.Value; // will not throw (safe lazy) if (value is SafeLazy.ExceptionHolder eh) { eh.Exception.Throw(); // throw once! } return(value); }
/// <inheritdoc /> public void Insert(string key, Func <object> factory, TimeSpan?timeout = null, bool isSliding = false, string[] dependentFiles = null) { InnerCache.Insert(key, () => { var result = SafeLazy.GetSafeLazy(factory); var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache // do not store null values (backward compat), clone / reset to go into the cache return(value == null ? null : CheckCloneableAndTracksChanges(value)); }, timeout, isSliding, dependentFiles); }
/// <inheritdoc /> public object Get(string key, Func <object> factory) { var cached = InnerCache.Get(key, () => { var result = SafeLazy.GetSafeLazy(factory); var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache // do not store null values (backward compat), clone / reset to go into the cache return(value == null ? null : CheckCloneableAndTracksChanges(value)); }); return(CheckCloneableAndTracksChanges(cached)); }
/// <inheritdoc /> public override object Get(string key, Func <object> factory) { //no place to cache so just return the callback result if (!TryGetContextItems(out var items)) { return(factory()); } key = GetCacheKey(key); Lazy <object> result; try { EnterWriteLock(); result = items[key] as Lazy <object>; // null if key not found // cannot create value within the lock, so if result.IsValueCreated is false, just // do nothing here - means that if creation throws, a race condition could cause // more than one thread to reach the return statement below and throw - accepted. if (result == null || SafeLazy.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null { result = SafeLazy.GetSafeLazy(factory); items[key] = result; } } finally { ExitWriteLock(); } // using GetSafeLazy and GetSafeLazyValue ensures that we don't cache // exceptions (but try again and again) and silently eat them - however at // some point we have to report them - so need to re-throw here // this does not throw anymore //return result.Value; var value = result.Value; // will not throw (safe lazy) if (value is SafeLazy.ExceptionHolder eh) { eh.Exception.Throw(); // throw once! } return(value); }
/// <inheritdoc /> public void Insert(string key, Func <object> factory, TimeSpan?timeout = null, bool isSliding = false, string[] dependentFiles = null) { // NOTE - here also we must insert a Lazy<object> but we can evaluate it right now // and make sure we don't store a null value. var result = SafeLazy.GetSafeLazy(factory); var value = result.Value; // force evaluation now if (value == null) { return; // do not store null values (backward compat) } var policy = GetPolicy(timeout, isSliding, dependentFiles); //NOTE: This does an add or update MemoryCache.Set(key, result, policy); }
/// <inheritdoc /> public object Get(string cacheKey, Func <object> getCacheItem) { var result = _items.GetOrAdd(cacheKey, k => SafeLazy.GetSafeLazy(getCacheItem)); var value = result.Value; // will not throw (safe lazy) if (!(value is SafeLazy.ExceptionHolder eh)) { return(value); } // and... it's in the cache anyway - so contrary to other cache providers, // which would trick with GetSafeLazyValue, we need to remove by ourselves, // in order NOT to cache exceptions _items.TryRemove(cacheKey, out result); eh.Exception.Throw(); // throw once! return(null); // never reached }