/// <summary>
        /// Reads the entity from the cache using the entity reference.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="reference">The key value pair.</param>
        /// <returns>Returns the response holder.</returns>
        public override async Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                var resolve = await RedisResolveReference(transform, reference);

                if (resolve.Item1)
                {
                    return(await Read(transform, resolve.Item2));
                }

                return(new PersistenceResponseHolder <E>()
                {
                    StatusCode = 404, IsSuccess = false
                });
            }
            catch (Exception)
            {
                return(new PersistenceResponseHolder <E>()
                {
                    StatusCode = 500, IsSuccess = false
                });
            }
        }
        /// <summary>
        /// This method writes out the references for the entity.
        /// </summary>
        /// <param name="transform">The entity transform.</param>
        /// <param name="reference">The reference.</param>
        /// <param name="key">The root key.</param>
        /// <param name="version">The entity version.</param>
        /// <param name="expiry">Optional expiry timespan for the key</param>
        /// <returns>Returns an async task.</returns>
        public override async Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                IDatabase rDb   = mLazyConnection.Value.GetDatabase();
                IBatch    batch = rDb.CreateBatch();
                var       tasks = new List <Task>(WriteReference(batch, transform, reference, key, version, expiry));
                batch.Execute();

                await Task.WhenAll(tasks);

                return(true);
            }
            catch (Exception)
            {
                // Don't raise an exception here
            }

            return(false);
        }
        /// <summary>
        /// Reads the entity from the cache, if it is present.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="key">The entity key.</param>
        /// <returns>Returns the response holder.</returns>
        public override async Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, K key)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }
            try
            {
                IDatabase rDb     = mLazyConnection.Value.GetDatabase();
                RedisKey  hashkey = RedisKeyGet(transform, key);

                //Entity
                RedisValue result = await rDb.HashGetAsync(hashkey, cnKeyEntity);

                if (result.HasValue)
                {
                    var entity = transform.CacheEntitySerializer.Deserializer(result);
                    return(new PersistenceResponseHolder <E> {
                        StatusCode = 200, Content = result, IsSuccess = true, Entity = entity, Id = transform.KeySerializer(key), VersionId = transform.Version?.EntityVersionAsString(entity)
                    });
                }

                return(new PersistenceResponseHolder <E> {
                    StatusCode = 404, IsSuccess = false
                });
            }
            catch (Exception)
            {
                return(new PersistenceResponseHolder <E> {
                    StatusCode = 500, IsSuccess = false
                });
            }
        }
        /// <summary>
        /// Writes the version out for the entity key
        /// </summary>
        /// <param name="transform"></param>
        /// <param name="key"></param>
        /// <param name="version"></param>
        /// <param name="expiry"></param>
        /// <returns></returns>
        public override async Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                IDatabase rDb     = mLazyConnection.Value.GetDatabase();
                IBatch    batch   = rDb.CreateBatch();
                RedisKey  hashkey = RedisKeyGet(transform, key);

                var tasks = new List <Task>
                {
                    //Version
                    batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always),
                    // Expiry
                    batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl)
                };
                batch.Execute();

                await Task.WhenAll(tasks);

                return(true);
            }
            catch (Exception)
            {
                // Don't raise an exception here
            }
            return(false);
        }
        /// <summary>
        /// This private method is used to resolve a lookup reference from the cache.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="reference">The tuple type/value pair.</param>
        /// <returns>Returns triple with the first boolean property indicating success followed by the key and the version.</returns>
        private async Task <Tuple <bool, K, string> > RedisResolveReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
        {
            if (transform.KeyDeserializer != null)
            {
                try
                {
                    IDatabase rDb     = mLazyConnection.Value.GetDatabase();
                    RedisKey  hashkey = RedisReferenceKeyGet(transform, transform.ReferenceHashMaker(reference));

                    //Entity
                    RedisValue enitityId = await rDb.HashGetAsync(hashkey, cnKeyEntityId);

                    if (enitityId.HasValue)
                    {
                        K key = transform.KeyDeserializer(enitityId);
                        return(new Tuple <bool, K, string>(true, key, await rDb.HashGetAsync(hashkey, cnKeyVersion)));
                    }
                }
                catch (Exception)
                {
                    // Don't raise an exception here
                }
            }

            return(new Tuple <bool, K, string>(false, default(K), null));
        }
Exemple #6
0
        /// <summary>
        /// The transform holder manages the serialization and deserialization of the entity and key
        /// for the entity and key, and identifies the references for the entity.
        /// </summary>
        /// <param name="entityName">The entity name.</param>
        /// <param name="versionPolicy">The version policy for the entity.</param>
        /// <param name="keyMaker">The keymaker function that creates a key for the entity.</param>
        /// <param name="persistenceEntitySerializer">Used to serialize / deserialize for persistence</param>
        /// <param name="cachingEntitySerializer">Used to serialize / deserialize for caching</param>
        /// <param name="keySerializer">The serializer that converts the key in to a string.</param>
        /// <param name="keyDeserializer">The deserializer that converts a string in to a key.</param>
        /// <param name="referenceMaker">A function that returns references from the entity in a set of string Tuples.</param>
        /// <param name="referenceHashMaker">A function that creates a safe hash from the reference tuple</param>
        /// <returns>Returns the transform holder.</returns>
        protected virtual EntityTransformHolder <K, E> EntityTransformCreate(
            string entityName = null
            , VersionPolicy <E> versionPolicy = null
            , Func <E, K> keyMaker            = null
            , EntitySerializer <E> persistenceEntitySerializer = null
            , EntitySerializer <E> cachingEntitySerializer     = null
            , Func <K, string> keySerializer   = null
            , Func <string, K> keyDeserializer = null
            , Func <E, IEnumerable <Tuple <string, string> > > referenceMaker = null
            , Func <Tuple <string, string>, string> referenceHashMaker        = null)
        {
            var transform = new EntityTransformHolder <K, E>
            {
                KeyMaker                    = keyMaker,
                KeySerializer               = keySerializer ?? (i => i.ToString()),
                KeyDeserializer             = keyDeserializer,
                ReferenceMaker              = referenceMaker ?? (e => new Tuple <string, string>[] {}),
                ReferenceHashMaker          = referenceHashMaker ?? (r => $"{r.Item1.ToLowerInvariant()}.{r.Item2.ToLowerInvariant()}"),
                Version                     = versionPolicy ?? new VersionPolicy <E>(),
                EntityName                  = entityName ?? typeof(E).Name.ToLowerInvariant(),
                PersistenceEntitySerializer = persistenceEntitySerializer,
                CacheEntitySerializer       = cachingEntitySerializer,
            };

            return(transform);
        }
Exemple #7
0
        /// <summary>
        /// This constructor specifies whether the service should be registered as a shared service
        /// that can be called directly by other message handler and Microservice components.
        /// </summary>
        /// <param name="persistenceRetryPolicy"></param>
        /// <param name="resourceProfile"></param>
        /// <param name="cacheManager"></param>
        /// <param name="defaultTimeout"></param>
        /// <param name="entityName"></param>
        /// <param name="versionPolicy"></param>
        /// <param name="keyMaker"></param>
        /// <param name="persistenceEntitySerializer"></param>
        /// <param name="cachingEntitySerializer"></param>
        /// <param name="keySerializer"></param>
        /// <param name="keyDeserializer"></param>
        /// <param name="referenceMaker"></param>
        /// <param name="referenceHashMaker"></param>
        protected PersistenceCommandBase(
            PersistenceRetryPolicy persistenceRetryPolicy = null
            , ResourceProfile resourceProfile             = null
            , ICacheManager <K, E> cacheManager           = null
            , TimeSpan?defaultTimeout         = null
            , string entityName               = null
            , VersionPolicy <E> versionPolicy = null
            , Func <E, K> keyMaker            = null
            , EntitySerializer <E> persistenceEntitySerializer = null
            , EntitySerializer <E> cachingEntitySerializer     = null
            , Func <K, string> keySerializer   = null
            , Func <string, K> keyDeserializer = null
            , Func <E, IEnumerable <Tuple <string, string> > > referenceMaker = null
            , Func <Tuple <string, string>, string> referenceHashMaker        = null
            )
        {
            mTransform = EntityTransformCreate(entityName, versionPolicy, keyMaker
                                               , persistenceEntitySerializer, cachingEntitySerializer
                                               , keySerializer, keyDeserializer, referenceMaker, referenceHashMaker);

            mRequestsCurrent = new ConcurrentDictionary <Guid, IPersistenceRequestHolder>();

            mPolicy.DefaultTimeout         = defaultTimeout ?? TimeSpan.FromSeconds(10);
            mPolicy.PersistenceRetryPolicy = persistenceRetryPolicy ?? new PersistenceRetryPolicy();
            mPolicy.ResourceProfile        = resourceProfile;

            mCacheManager = cacheManager ?? new NullCacheManager <K, E>();
        }
        public RedisCacheManager(string connection, bool readOnly = true, EntityTransformHolder <K, E> transform = null, TimeSpan?entityTtl = null)
            : base(readOnly)
        {
            mConnection = connection;
            mTransform  = transform ?? new EntityTransformHolder <K, E>(true);

            mEntityTtl      = entityTtl ?? TimeSpan.FromDays(2);
            mLazyConnection = new Lazy <ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(mConnection));
        }
        /// <summary>
        /// This method writes out the references for the entity.
        /// </summary>
        /// <param name="batch">The redis batch.</param>
        /// <param name="transform">The entity transform.</param>
        /// <param name="reference">The reference.</param>
        /// <param name="key">The root key.</param>
        /// <param name="version">The entity version.</param>
        /// <param name="expiry">Expiry time of the key</param>
        /// <returns>Returns an async task.</returns>
        protected virtual List <Task> WriteReference(IBatch batch, EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null)
        {
            //entityreference.{entitytype}.{keytype i.e., EMAIL, ID etc.}
            RedisKey hashkey = RedisReferenceKeyGet(transform, transform.ReferenceHashMaker(reference));

            return(new List <Task>(3)
            {
                batch.HashSetAsync(hashkey, cnKeyEntityId, transform.KeySerializer(key), when: When.Always),
                batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always),
                batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl)
            });
        }
        /// <summary>
        /// This method writes the entity to the redis cache.
        /// </summary>
        /// <param name="transform">The transform holder.</param>
        /// <param name="entity">The entity to write.</param>
        /// <param name="expiry"></param>
        /// <returns>Returns true if the write was successful.</returns>
        public override async Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                K      key     = transform.KeyMaker(entity);
                string version = transform.Version.EntityVersionAsString(entity);

                IDatabase rDb     = mLazyConnection.Value.GetDatabase();
                IBatch    batch   = rDb.CreateBatch();
                RedisKey  hashkey = RedisKeyGet(transform, key);

                var tasks = new List <Task>
                {
                    //Entity
                    batch.HashSetAsync(hashkey, cnKeyEntity, transform.CacheEntitySerializer.Serializer(entity), when: When.Always),
                    //Version
                    batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always),
                    // Expiry
                    batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl)
                };

                //Get any associated references for the entity.
                var references = transform.ReferenceMaker(entity);
                references?.ForEach(r => tasks.AddRange(WriteReference(batch, transform, r, key, version)));

                batch.Execute();

                await Task.WhenAll(tasks);

                return(true);
            }
            catch (Exception)
            {
                // Don't raise an exception here
            }

            return(false);
        }
Exemple #11
0
        /// <summary>
        /// This constructor specifies whether the service should be registered as a shared service
        /// that can be called directly by other message handler and Microservice components.
        /// </summary>
        protected PersistenceCommandBase(
            EntityTransformHolder <K, E> entityTransform
            , PersistenceRetryPolicy persistenceRetryPolicy = null
            , ResourceProfile resourceProfile   = null
            , ICacheManager <K, E> cacheManager = null
            , TimeSpan?defaultTimeout           = null
            )
        {
            if (entityTransform == null)
            {
                throw new ArgumentNullException("entityTransform cannot be null");
            }

            mTransform = entityTransform;

            mPolicy.DefaultTimeout         = defaultTimeout ?? TimeSpan.FromSeconds(10);
            mPolicy.PersistenceRetryPolicy = persistenceRetryPolicy ?? new PersistenceRetryPolicy();
            mPolicy.ResourceProfile        = resourceProfile;

            mCacheManager = cacheManager ?? new NullCacheManager <K, E>();
        }
        /// <summary>
        /// This method deletes from the cache.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="key">The entity key.</param>
        /// <returns>Returns true if the entity was deleted from the cache.</returns>
        public override async Task <bool> Delete(EntityTransformHolder <K, E> transform, K key)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            if (IsReadOnly)
            {
                return(false);
            }

            try
            {
                IDatabase rDb   = mLazyConnection.Value.GetDatabase();
                IBatch    batch = rDb.CreateBatch();

                var      tasks   = new List <Task>();
                RedisKey hashkey = RedisKeyGet(transform, key);

                //Entity
                tasks.Add(batch.HashDeleteAsync(hashkey, cnKeyEntity));
                //Version
                tasks.Add(batch.HashDeleteAsync(hashkey, cnKeyVersion));

                batch.Execute();

                await Task.WhenAll(tasks);

                return(true);
            }
            catch (Exception)
            {
                // Don't raise an exception here
            }

            return(false);
        }
        /// <summary>
        /// This method resolves the reference from the cache and then deletes the entity.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="reference">The key/value reference pair.</param>
        /// <returns>Returns true if the entity was deleted from the cache.</returns>
        public override async Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                var resolve = await RedisResolveReference(transform, reference);

                if (resolve.Item1)
                {
                    return(await Delete(transform, resolve.Item2));
                }
            }
            catch (Exception)
            {
                // Don't raise and exception here
            }

            return(false);
        }
Exemple #14
0
 public override Task <bool> Delete(EntityTransformHolder <K, E> transform, K key)
 {
     return(Task.FromResult(false));
 }
Exemple #15
0
 public override Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
 {
     return(Task.FromResult(new PersistenceResponseHolder <E> {
         IsSuccess = false, StatusCode = 404
     } as IResponseHolder <E>));
 }
 public abstract Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null);
Exemple #17
0
 public override Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
 {
     return(Task.FromResult(false));
 }
 public abstract Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference);
 public abstract Task <bool> Delete(EntityTransformHolder <K, E> transform, K key);
 /// <summary>
 /// This method creates the reference collection key for an entity reference.
 /// </summary>
 /// <param name="transform">The transform object.</param>
 /// <param name="referenceHash">The hash of the reference i.e. [email protected] / custoemerid.123456</param>
 /// <returns>Returns the appropriate redis key.</returns>
 protected virtual RedisKey RedisReferenceKeyGet(EntityTransformHolder <K, E> transform, string referenceHash)
 {
     //entityreference.{entitytype}.{keytype i.e., EMAIL, ID etc.}.{[email protected]}
     return($"entityreference.{transform.EntityName}.{referenceHash}");
 }
 /// <summary>
 /// Configures the specified container.
 /// </summary>
 /// <param name="transform">The persistence transform entity.</param>
 public virtual void Configure(EntityTransformHolder <K, E> transform)
 {
     Transform = transform;
 }
 /// <summary>
 /// This method creates the hash table key to hold the entity information in Redis cache.
 /// </summary>
 /// <param name="transform">The transform object.</param>
 /// <param name="key">The entity key.</param>
 /// <returns>Returns the redis key.</returns>
 protected virtual RedisKey RedisKeyGet(EntityTransformHolder <K, E> transform, K key)
 {
     return($"entity.{transform.EntityName}.{transform.KeySerializer(key)}");
 }
        /// <summary>
        /// This method returns the reference key and version for the suple reftype/value pair.
        /// </summary>
        /// <param name="transform">The transform.</param>
        /// <param name="reference">The tuple reference.</param>
        /// <returns>Returns the response holder with a response code of 200 if successful</returns>
        public override async Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, Tuple <string, string> reference)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }

            try
            {
                var resolve = await RedisResolveReference(transform, reference);

                if (resolve.Item1)
                {
                    return new PersistenceResponseHolder <Tuple <K, string> > {
                               StatusCode = 200, IsSuccess = true, Id = transform.KeySerializer(resolve.Item2), VersionId = resolve.Item3, Entity = new Tuple <K, string>(resolve.Item2, resolve.Item3)
                    }
                }
                ;

                return(new PersistenceResponseHolder <Tuple <K, string> > {
                    StatusCode = 404, IsSuccess = false
                });
            }
            catch (Exception)
            {
                return(new PersistenceResponseHolder <Tuple <K, string> > {
                    StatusCode = 500, IsSuccess = false
                });
            }
        }
 public abstract Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null);
Exemple #25
0
 public override Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null)
 {
     return(Task.FromResult(false));
 }
Exemple #26
0
 public override Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, K key)
 {
     return(Task.FromResult(new PersistenceResponseHolder <E> {
         IsSuccess = false, StatusCode = 404
     } as IResponseHolder <Tuple <K, string> >));
 }
Exemple #27
0
 public override Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null)
 {
     return(Task.FromResult(false));
 }
        /// <summary>
        /// This method reads the version from the cache.
        /// </summary>
        /// <param name="transform">The entity transform.</param>
        /// <param name="key">The entity key.</param>
        /// <returns>Returns the async task.</returns>
        public override async Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, K key)
        {
            if (transform == null)
            {
                throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null.");
            }
            try
            {
                IDatabase rDb     = mLazyConnection.Value.GetDatabase();
                RedisKey  hashkey = RedisKeyGet(transform, key);

                //Entity
                RedisValue result = await rDb.HashGetAsync(hashkey, cnKeyVersion);

                if (result.HasValue)
                {
                    return new PersistenceResponseHolder <Tuple <K, string> > {
                               StatusCode = 200, IsSuccess = true, VersionId = result, Id = transform.KeySerializer(key), Entity = new Tuple <K, string>(key, result)
                    }
                }
                ;

                return(new PersistenceResponseHolder <Tuple <K, string> > {
                    StatusCode = 404, IsSuccess = false
                });
            }
            catch (Exception)
            {
                return(new PersistenceResponseHolder <Tuple <K, string> > {
                    StatusCode = 500, IsSuccess = false
                });
            }
        }
Exemple #29
0
 public override Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null)
 {
     return(Task.FromResult(false));
 }
 public abstract Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null);