/// <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());
        }
Example #2
0
 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);
 });
Example #3
0
        public async Task <bool> Delete(IStorableObject o)
        {
            await cache.InvalidateObject <IStorableObject>(o.CacheKey);

            Debug.WriteLine("Deleting from the cache: {0} ", o);
            return(true);
        }
Example #4
0
        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);
        }
Example #5
0
        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());
        }
Example #6
0
        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));
        }
Example #7
0
 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);
 }
Example #9
0
        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());
        }
Example #10
0
        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));
        }
Example #11
0
        /// <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());
        }
Example #12
0
        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());
        }
Example #13
0
 public async Task Remove <T>(string key)
 {
     await _cache.InvalidateObject <T>(GetKey(key));
 }
 public void InvalidateCache <T>(string key)
 {
     Cache.InvalidateObject <T>(key);
 }
Example #15
0
 /// <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);
 }
Example #16
0
 public async Task RemoveObject <T>(Guid id)
 {
     await Storage.InvalidateObject <T>(id.ToString());
 }
Example #17
0
 public static async Task RemoveDestination(Guid id)
 {
     await Cache.InvalidateObject <Destination>(id.ToString());
 }
 public IObservable <Unit> DeleteAll()
 {
     return(blob.InvalidateObject <IList <Session> >(KEY_SESSIONS));
 }
Example #19
0
 public void Delete <T>(string key)
 {
     _cache.InvalidateObject <T>(key).ToTask().Wait();
 }