/// <summary> /// This method attempts to returned a cached value, while /// simultaneously calling a Func to return the latest value. When the /// latest data comes back, it replaces what was previously in the /// cache. /// /// This method is best suited for loading dynamic data from the /// Internet, while still showing the user earlier data. /// /// This method returns an IObservable that may return *two* results /// (first the cached data, then the latest data). Therefore, it's /// important for UI applications that in your Subscribe method, you /// write the code to merge the second result when it comes in. /// /// This also means that await'ing this method is a Bad Idea(tm), always /// use Subscribe. /// </summary> /// <param name="key">The key to store the returned result under.</param> /// <param name="fetchFunc"></param> /// <param name="fetchPredicate">An optional Func to determine whether /// the updated item should be fetched. If the cached version isn't found, /// this parameter is ignored and the item is always fetched.</param> /// <param name="absoluteExpiration">An optional expiration date.</param> /// <param name="shouldInvalidateOnError">If this is true, the cache will /// be cleared when an exception occurs in fetchFunc</param> /// <returns>An Observable stream containing either one or two /// results (possibly a cached version, then the latest version)</returns> public static IObservable <T> GetAndFetchLatest <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null, bool shouldInvalidateOnError = false) { var fetch = Observable.Defer(() => This.GetObjectCreatedAt <T>(key)) .Select(x => fetchPredicate == null || x == null || fetchPredicate(x.Value)) .Where(x => x != false) .SelectMany(_ => { var fetchObs = fetchFunc().Catch <T, Exception>(ex => { var shouldInvalidate = shouldInvalidateOnError ? This.InvalidateObject <T>(key) : Observable.Return(Unit.Default); return(shouldInvalidate.SelectMany(__ => Observable.Throw <T>(ex))); }); return(fetchObs .SelectMany(x => This.InvalidateObject <T>(key).Select(__ => x)) .SelectMany(x => This.InsertObject <T>(key, x, absoluteExpiration).Select(__ => x))); }); var result = This.GetObject <T>(key).Select(x => new Tuple <T, bool>(x, true)) .Catch(Observable.Return(new Tuple <T, bool>(default(T), false))); return(result.SelectMany(x => { return x.Item2 ? Observable.Return(x.Item1) : Observable.Empty <T>(); }).Concat(fetch).Multicast(new ReplaySubject <T>()).RefCount()); }
public Task Remove(Guid id) => Task.Run(() => { var persistentId = id.ToString(); _blobCache.InvalidateObject <ProviderModel>(persistentId).Subscribe(); var provider = _connectable.Items.First(x => x.Id == id); _connectable.Remove(provider); });
public async Task <bool> Delete(IStorableObject o) { await cache.InvalidateObject <IStorableObject>(o.CacheKey); Debug.WriteLine("Deleting from the cache: {0} ", o); return(true); }
public async Task <bool> Delete <T>(T entity) where T : EntityBase, new() { try { // Aquí se haría la llamada con await a la API Rest con _remoteDatabase para BORRAR el elemento en el servidor // Si ha ido bien se hace lo mismo en caché await _cache.InvalidateObject <T>(typeof(T).Name + "_" + entity.id.ToString()); } catch (Exception) { return(false); } return(true); }
static IObservable <T> GetAndFetchLatestFromIndex <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, Action <T> removedItemsCallback, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null, bool shouldInvalidateOnError = false) where T : CacheItem { var idx = Observable.Defer(() => This .GetOrCreateObject(key, () => CacheIndex.Create(key))) .Select(x => x.IndexKey == null ? CacheIndex.Create(key) : x) .Replay() .RefCount(); var fetch = idx .Select(x => Tuple.Create(x, fetchPredicate == null || !x.Keys.Any() || fetchPredicate(x.UpdatedAt))) .Where(predicateIsTrue => predicateIsTrue.Item2) .Select(x => x.Item1) .Select(index => index.Clear()) .SelectMany(index => fetchFunc() .Catch <T, Exception>(ex => { var shouldInvalidate = shouldInvalidateOnError ? This.InvalidateObject <CacheIndex>(key) : Observable.Return(Unit.Default); return(shouldInvalidate.SelectMany(__ => Observable.Throw <T>(ex))); }) .SelectMany(x => x.Save <T>(This, key, absoluteExpiration)) .Do(x => index.Add(key, x)) ); var cache = idx .SelectMany(index => This.GetObjects <T>(index.Keys.ToList())) .SelectMany(dict => dict.Values); return(cache.Merge(fetch) .Finally(async() => { var index = await idx; await index.Save(This); var list = index.OldKeys.Except(index.Keys); if (!list.Any()) { return; } var removed = await This.GetObjects <T>(list); foreach (var d in removed.Values) { removedItemsCallback(d); } await This.InvalidateObjects <T>(list); }) .Replay().RefCount()); }
public IObservable <T> Save <T>(IBlobCache cache, string key, DateTimeOffset?absoluteExpiration = null) where T : CacheItem { var k = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", key, Key); return(cache .InvalidateObject <T>(k) .Select(_ => cache.InsertObject(k, this, absoluteExpiration)) .Select(_ => this as T)); }
public IObservable <CacheIndex> Clear(IBlobCache cache, string indexKey, DateTimeOffset?absoluteExpiration = null) { OldKeys = Keys.ToList(); Keys.Clear(); UpdatedAt = DateTimeOffset.UtcNow; return(cache .InvalidateObject <CacheIndex>(indexKey) .SelectMany(_ => cache.InsertObject(indexKey, this, absoluteExpiration)) .Select(_ => this)); }
public IObservable<CacheIndex> Clear(IBlobCache cache, string indexKey, DateTimeOffset? absoluteExpiration = null) { OldKeys = Keys.ToList(); Keys.Clear(); UpdatedAt = DateTimeOffset.UtcNow; return cache .InvalidateObject<CacheIndex>(indexKey) .SelectMany(_ => cache.InsertObject(indexKey, this, absoluteExpiration)) .Select(_ => this); }
public static IObservable <T?> GetAndFetchLatest <T>( this IBlobCache blobCache, string key, Func <IObservable <T> > fetchFunc, Func <DateTimeOffset, bool>?fetchPredicate = null, DateTimeOffset?absoluteExpiration = null, bool shouldInvalidateOnError = false, Func <T, bool>?cacheValidationPredicate = null) { if (blobCache is null) { throw new ArgumentNullException(nameof(blobCache)); } #pragma warning disable CS8604 // Possible null reference argument. var fetch = Observable.Defer(() => blobCache.GetObjectCreatedAt <T>(key)) .Select(x => fetchPredicate is null || x is null || fetchPredicate(x.Value)) .Where(x => x) .SelectMany(_ => { var fetchObs = fetchFunc().Catch <T, Exception>(ex => { var shouldInvalidate = shouldInvalidateOnError ? blobCache.InvalidateObject <T>(key) : Observable.Return(Unit.Default); return(shouldInvalidate.SelectMany(__ => Observable.Throw <T>(ex))); }); return(fetchObs .SelectMany(x => cacheValidationPredicate is not null && !cacheValidationPredicate(x) ? Observable.Return(default(T)) : blobCache.InvalidateObject <T>(key).Select(__ => x)) .SelectMany(x => cacheValidationPredicate is not null && !cacheValidationPredicate(x) ? Observable.Return(default(T)) : blobCache.InsertObject(key, x, absoluteExpiration).Select(__ => x))); }); if (fetch is null) { return(Observable.Throw <T>(new Exception("Could not find a valid way to fetch the value"))); } var result = blobCache.GetObject <T>(key).Select(x => (x, true)) .Catch(Observable.Return((default(T), false))); #pragma warning restore CS8604 // Possible null reference argument. return(result.SelectMany(x => x.Item2 ? Observable.Return(x.Item1) : Observable.Empty <T>()) .Concat(fetch) .Multicast(new ReplaySubject <T?>()) .RefCount()); }
public static IObservable <Unit> InvalidateObjects <T>(this IBlobCache This, IEnumerable <string> keys) { var bulkCache = This as IObjectBulkBlobCache; if (bulkCache != null) { return(bulkCache.InvalidateObjects <T>(keys)); } return(keys.ToObservable() .SelectMany(x => This.InvalidateObject <T>(x)) .TakeLast(1)); }
/// <summary> /// This method attempts to returned a cached value, while /// simultaneously calling a Func to return the latest value. When the /// latest data comes back, it replaces what was previously in the /// cache. /// /// This method is best suited for loading dynamic data from the /// Internet, while still showing the user earlier data. /// /// This method returns an IObservable that may return *two* results /// (first the cached data, then the latest data). Therefore, it's /// important for UI applications that in your Subscribe method, you /// write the code to merge the second result when it comes in. /// /// This also means that await'ing this method is a Bad Idea(tm), always /// use Subscribe. /// </summary> /// <param name="key">The key to store the returned result under.</param> /// <param name="fetchFunc"></param> /// <param name="fetchPredicate">An optional Func to determine whether /// the updated item should be fetched. If the cached version isn't found, /// this parameter is ignored and the item is always fetched.</param> /// <param name="absoluteExpiration">An optional expiration date.</param> /// <param name="shouldInvalidateOnError">If this is true, the cache will /// be cleared when an exception occurs in fetchFunc</param> /// <returns>An Observable stream containing either one or two /// results (possibly a cached version, then the latest version)</returns> public static IObservable <T> GetAndFetchLatest <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null, bool shouldInvalidateOnError = false) { var fetch = Observable.Defer(() => This.GetObjectCreatedAt <T>(key)) .Select(x => fetchPredicate == null || x == null || fetchPredicate(x.Value)) .Where(x => x != false) .SelectMany(async _ => { var ret = default(T); try { ret = await fetchFunc(); } catch (Exception) { if (shouldInvalidateOnError) { This.InvalidateObject <T>(key); } throw; } await This.InvalidateObject <T>(key); await This.InsertObject(key, ret, absoluteExpiration); return(ret); }); var result = This.GetObjectAsync <T>(key).Select(x => new Tuple <T, bool>(x, true)) .Catch(Observable.Return(new Tuple <T, bool>(default(T), false))); return(result.SelectMany(x => { return x.Item2 ? Observable.Return(x.Item1) : Observable.Empty <T>(); }).Concat(fetch).Multicast(new ReplaySubject <T>()).RefCount()); }
static IObservable <T> GetAndFetchLatestFromIndex <T>(this IBlobCache This, string key, Func <IObservable <T> > fetchFunc, Action <T> removedItemsCallback, Func <DateTimeOffset, bool> fetchPredicate = null, DateTimeOffset?absoluteExpiration = null, bool shouldInvalidateOnError = false) where T : CacheItem { var fetch = Observable.Defer(() => This.GetOrCreateObject(key, () => CacheIndex.Create(key)) .Select(x => Tuple.Create(x, fetchPredicate == null || !x.Keys.Any() || fetchPredicate(x.UpdatedAt))) .Where(predicateIsTrue => predicateIsTrue.Item2) .Select(x => x.Item1) .SelectMany(index => index.Clear(This, key, absoluteExpiration)) .SelectMany(index => { var fetchObs = fetchFunc().Catch <T, Exception>(ex => { var shouldInvalidate = shouldInvalidateOnError ? This.InvalidateObject <CacheIndex>(key) : Observable.Return(Unit.Default); return(shouldInvalidate.SelectMany(__ => Observable.Throw <T>(ex))); }); return(fetchObs .SelectMany(x => x.Save <T>(This, key, absoluteExpiration)) .Do(x => index.AddAndSave(This, key, x, absoluteExpiration)) .Finally(() => { This.GetObjects <T>(index.OldKeys.Except(index.Keys)) .Do(dict => This.InvalidateObjects <T>(dict.Keys)) .SelectMany(dict => dict.Values) .Do(removedItemsCallback) .Subscribe(); })); })); var cache = Observable.Defer(() => This.GetOrCreateObject(key, () => CacheIndex.Create(key)) .SelectMany(index => This.GetObjects <T>(index.Keys)) .SelectMany(dict => dict.Values)); return(cache.Merge(fetch).Replay().RefCount()); }
public async Task Remove <T>(string key) { await _cache.InvalidateObject <T>(GetKey(key)); }
public void InvalidateCache <T>(string key) { Cache.InvalidateObject <T>(key); }
/// <summary> /// Remove an entity by the given key from the store. /// </summary> /// <param name="entity">Source key to remove by.</param> public virtual async Task Remove<T>(T entity) where T : class, IKeyProvider { await _blobCache.InvalidateObject<T>(entity.Key); }
public async Task RemoveObject <T>(Guid id) { await Storage.InvalidateObject <T>(id.ToString()); }
public static async Task RemoveDestination(Guid id) { await Cache.InvalidateObject <Destination>(id.ToString()); }
public IObservable <Unit> DeleteAll() { return(blob.InvalidateObject <IList <Session> >(KEY_SESSIONS)); }
public void Delete <T>(string key) { _cache.InvalidateObject <T>(key).ToTask().Wait(); }