/// <summary> /// Returns true if data was retrieved /// </summary> /// <param name="onRefreshed">true if updated, false if from cache</param> public async Task <bool> WithRefreshAsync <T>(RequestToken token, string key, bool allowStaleData, bool forceRefresh, FetchedRequestDelegate <T> onRefreshed, Action <bool> onRefreshing, Func <Task <T> > createMethod) where T : class { this.EnsureInitialized(); IDataCacheFilter[] filters = this.Filters.Values.ToArray(); // see if we can use old data bool canReadCached = true; foreach (var item in filters) { if (!item.CanReadCached(this, key)) { canReadCached = false; break; } } T foundData = null; // use old data if we can if (allowStaleData && canReadCached && CachedData.ContainsKey(key)) { foundData = CachedData[key] as T; if (foundData == null) { forceRefresh = true; //had it, but it was bad data } } // see if we need to refresh if (!forceRefresh) { foreach (var item in filters) { if (item.RefreshRequired(this, key)) { forceRefresh = true; break; } } } if (foundData != null) { if (onRefreshed != null) { try { onRefreshed(token, false, foundData); // its not fresh } catch (Exception ex) { this.LogError(ex, "onRefreshed:old"); } } } // get the data if we need to if (foundData == null || forceRefresh || !canReadCached || !CachedData.ContainsKey(key)) { // single request at a time lock (_ExecutingLock) { if (this.Executing.Contains(key)) { return(false); } this.Executing.Add(key); } try { // get the data foreach (var item in filters) { item.OnBeforeItemRetrieved(this, key); } if (onRefreshing != null) { try { onRefreshing(true); } catch (Exception ex) { this.LogError(ex, "onRefreshing:true"); } } T data = null; if (createMethod != null) { data = await createMethod(); } foreach (var item in filters) { item.OnAfterItemRetrieved(this, key, data); } if (data != null) { bool canWriteToCache = true; foreach (var item in filters) { if (!item.CanSaveToCache(this, key, data)) { canWriteToCache = false; break; } } if (canWriteToCache) { foreach (var item in filters) { item.OnBeforeItemSavedToCache(this, key, data); } this.AddToCache(key, data); foreach (var item in filters) { item.OnAfterItemSavedToCache(this, key, data); } } if (onRefreshed != null) { try { onRefreshed(token, true, data); } catch (Exception ex) { this.LogError(ex, "onRefreshed:new"); } } return(true); } else { return(false); } } finally { lock (_ExecutingLock) { this.Executing.Remove(key); } if (onRefreshing != null) { try { onRefreshing(false); } catch (Exception ex) { this.LogError(ex, "onRefreshing:false"); } } } } else { if (onRefreshing != null) { try { onRefreshing(false); } catch (Exception ex) { this.LogError(ex, "onRefreshing:false"); } } return(false); } }