/// <summary> /// Refreshes if the prefix has timed out and/or the localkey has timed out. /// Flushes all items if the time out has occurred /// Returns true if data was retrieved /// </summary> /// </summary> public static async Task <bool> WithTimedRefreshForPrefixAsync <T>(this IDataCache dataCache, RequestToken requestToken, bool allowStale, string prefixKey, string localKey, int maximumStaleSeconds, FetchedRequestDelegate <T> onRefreshed, Action <bool> onRefreshing, Func <Task <T> > createMethod) where T : class { TimedDataCacheFilter timeFilter = EnsureTimedLifetimeFilter(dataCache); bool forceRefresh = (maximumStaleSeconds <= 0); if (!forceRefresh) { // use the passed in time to override the default forceRefresh = timeFilter.RefreshRequired(prefixKey, maximumStaleSeconds); } if (forceRefresh) { timeFilter.AddClearBeforeSave(localKey, prefixKey); } FetchedRequestDelegate <T> onRefreshedWrapper = (token, freshData, data) => { if (freshData) { dataCache.AddToCache(prefixKey, data); timeFilter.OnAfterItemSavedToCache(dataCache, prefixKey, data); } if (onRefreshed != null) { onRefreshed(token, freshData, data); } }; return(await dataCache.WithRefreshAsync <T>(requestToken, prefixKey + localKey, allowStale, forceRefresh, onRefreshedWrapper, onRefreshing, createMethod)); }
public Task <bool> WithRefreshAsync <T>(string key, bool allowStaleData, bool forceRefresh, FetchedDelegate <T> onRefreshed, Action <bool> onRefreshing, Func <Task <T> > createMethod) where T : class { FetchedRequestDelegate <T> wrapper = null; if (onRefreshed != null) { wrapper = (token, freshData, data) => { onRefreshed(freshData, data); }; } return(this.WithRefreshAsync <T>(RequestToken.Empty, key, allowStaleData, forceRefresh, wrapper, onRefreshing, createMethod)); }
public static async Task <bool> WithTimedRefreshAsync <T>(this IDataCache dataCache, RequestToken requestToken, string key, int maximumStaleSeconds, FetchedRequestDelegate <T> onRefreshed, Action <bool> onRefreshing, Func <Task <T> > createMethod) where T : class { TimedDataCacheFilter timeFilter = EnsureTimedLifetimeFilter(dataCache); bool forceRefresh = (maximumStaleSeconds <= 0); bool allowStale = (maximumStaleSeconds != 0); if (!forceRefresh) { // use the passed in time to override the default forceRefresh = timeFilter.RefreshRequired(key, maximumStaleSeconds); } return(await dataCache.WithRefreshAsync <T>(requestToken, key, allowStale, forceRefresh, onRefreshed, onRefreshing, createMethod)); }
/// <summary> /// Fetches list data with support for cached data and timeouts /// </summary> protected virtual Task <bool> FetchListAsync <TData, TMeta>(RequestToken requestToken, bool allowStale, string cachePrefixKey, string cacheSpecificKey, int staleLimit, FetchedRequestDelegate <ListResult <TData, TMeta> > onFetched, Action <bool> onFetching, Func <Task <ListResult <TData, TMeta> > > fetchMethod) where TMeta : new() { try { return(this.DataCache.WithTimedRefreshForPrefixAsync <ListResult <TData, TMeta> >(requestToken, allowStale, cachePrefixKey, cacheSpecificKey, staleLimit, onFetched, onFetching, async delegate() { return await fetchMethod(); })); } catch (Exception ex) { EndpointException endpointException = ex.FirstExceptionOfType <EndpointException>(); if (endpointException != null) { switch (endpointException.StatusCode) { case HttpStatusCode.BadRequest: case HttpStatusCode.Unauthorized: case HttpStatusCode.Forbidden: case HttpStatusCode.NotFound: case HttpStatusCode.RequestTimeout: case HttpStatusCode.InternalServerError: case HttpStatusCode.NotImplemented: case HttpStatusCode.ServiceUnavailable: this.ViewPlatform.ShowToast("Error connecting to server. Please check connection."); break; default: break; } } this.ProcessExecuteException(ex, "FetchListAsync"); throw; } }
/// <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); } }