AOP緩存實現

輸入參數索引做爲緩存鍵的實現緩存

using MJD.Framework.CrossCutting;
using MJD.Framework.ICache;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 方法的緩存屬性(線性不安全)
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class CacheAttribute : AopAttribute
    {
        #region fields
        private short _index1 = -1;
        private short _index2 = -1;
        private short _index3 = -1;
        #endregion

        #region protected fields
        protected string Prefix = string.Empty;//緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴
        protected string Key = string.Empty;
        protected string BucketName = string.Empty;
        #endregion

        #region Otors
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        protected CacheAttribute(string bucketName, string prefix)
        {
            BucketName = bucketName;
            Prefix = prefix;
        }
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="key">緩存鍵</param>
        public CacheAttribute(string bucketName, string prefix, string key)
            : this(bucketName, prefix)
        {
            if (string.IsNullOrEmpty(key)) throw new ArgumentException("緩存鍵不能爲空");
            Key = string.Format("{0}:{1}", Prefix, key);
        }

        /// <summary>
        /// 使用當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex">對應的當前參數的緩存鍵所在的參數索引位置</param>
        public CacheAttribute(string bucketName, string prefix, short keyIndex)
            : this(bucketName, prefix)
        {
            if (keyIndex < 0) throw new ArgumentException("關鍵值的參數索引需大於0");
            _index1 = keyIndex;
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        public CacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
            : this(bucketName, prefix)
        {
            if (keyIndex1 < 0 || keyIndex2 < 0) throw new ArgumentException("關鍵值的參數索引需大於0");
            _index1 = keyIndex1;
            _index2 = keyIndex2;
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        /// <param name="keyIndex3">對應的當前參數的緩存鍵所在的參數索引位置3</param>
        public CacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
            : this(bucketName, prefix)
        {
            if (keyIndex1 < 0 || keyIndex2 < 0 || keyIndex3 < 0) throw new ArgumentException("關鍵值的參數索引不能小於零");
            _index1 = keyIndex1;
            _index2 = keyIndex2;
            _index3 = keyIndex3;
        }
        #endregion

        #region override

        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            outputs = new object[0];

            var result = IocContainer.Resolve<ICacheService>(BucketName).Get<object>(GetKey(inputArgs));
            return result.Success ? result.Value : null;
        }

        public override void Called(object resultValue, object[] inputArgs, object[] outputs)
        {
            IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
        }

        public override void OnException(Exception e, Dictionary<string, object> inputArgs)
        {
        }

        protected virtual string GetKey(object[] inputArgs)
        {
            if (string.IsNullOrEmpty(Key))
            {
                if (Math.Max(Math.Max(_index1, _index2), _index3) >= inputArgs.Count()) throw new ArgumentException("關鍵值的參數索引不能大於參數總個數");
                string prefix1 = _index1 >= 0 ? inputArgs[_index1].ToJson() : "";
                string prefix2 = _index2 >= 0 ? "-" + inputArgs[_index2].ToJson() : "";
                string prefix3 = _index3 >= 0 ? "-" + inputArgs[_index3].ToJson() : "";
                Key = string.Format("{0}:{1}{2}{3}",Prefix, prefix1, prefix2, prefix3);
            }
            return Key;
        }

        #endregion
    }
}

輸入參數是對象,經過輸入參數對象的屬性的值來做爲緩存鍵安全

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 根據屬性來設置緩存的關鍵字
    /// </summary>
    public class CacheWithPropertyAttribute : CacheAttribute
    {
        #region fields
        private List<string> _properties = null;
        private byte _index = 0;
        #endregion

        #region Octors
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存Bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="properties">屬性名</param>
        public CacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
            : base(bucketName, prefix)
        {
            if (properties == null || properties.Length == 0) throw new ArgumentException("設置的properties個數必須大於1");
            _properties = properties.ToList();
        }
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="index">要設置爲緩存的方法參數的索引,索引下標從0開始</param>
        /// <param name="properties">屬性名</param>
        public CacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
            : base(bucketName, prefix)
        {
            if (index < 0) throw new ArgumentException("關鍵值的參數索引不能小於零");
            if (properties == null || properties.Length == 0) throw new ArgumentException("設置的properties個數必須大於1");
            _properties = properties.ToList();
            _index = index;
        }
        #endregion

        #region override
        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            return base.PreCall(inputArgs, out outputs);
        }
        #endregion

        protected override string GetKey(object[] inputArgs)
        {
            if (string.IsNullOrEmpty(Key))
            {
                Key += base.Prefix + ":";
                object instance = inputArgs[_index];
                foreach (var property in _properties)
                {
                    Key += GetPropertyValue(instance, property) + "-";
                }
            }
            return Key.TrimEnd('-');
        }

        private object GetPropertyValue(object instance, string propertyName)
        {
            BindingFlags flag = BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.IgnoreCase | BindingFlags.Public;
            Type type = instance.GetType();
            var property = type.GetProperty(propertyName, flag);
            if (property == null) throw new ArgumentException(string.Format("獲取緩存出錯,類型{0}中沒有找到屬性{1}", type, propertyName));
            return property.GetValue(instance, null);
        }
    }
}

 

經過輸入參數索引位置移除緩存的aop屬性ide

using MJD.Framework.CrossCutting;
using MJD.Framework.ICache;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 移除緩存特性
    /// </summary>
    public class RemoveCacheAttribute : CacheAttribute
    {
        #region Otors
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        protected RemoveCacheAttribute(string bucketName, string prefix)
            : base(bucketName, prefix)
        {
        }
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="key">緩存鍵</param>
        public RemoveCacheAttribute(string bucketName, string prefix, string key)
            : base(bucketName, prefix, key)
        {
        }

        /// <summary>
        /// 使用當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex">對應的當前參數的緩存鍵所在的參數索引位置</param>
        public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex)
            : base(bucketName, prefix, keyIndex)
        {
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
            : base(bucketName, prefix, keyIndex1, keyIndex2)
        {
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        /// <param name="keyIndex3">對應的當前參數的緩存鍵所在的參數索引位置3</param>
        public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
            : base(bucketName, prefix, keyIndex1, keyIndex2, keyIndex3)
        {
        }
        #endregion

        #region override
        public override void Called(object resultValue, object[] inputArgs, object[] outputs)
        {
        }

        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
            outputs = new object[0];
            return null;
        }
        #endregion
    }
}

 經過輸入參數屬性的值做爲緩存鍵來移除緩存this

using MJD.Framework.CrossCutting;
using MJD.Framework.ICache;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 移除緩存特性(調用成功後移除)
    /// </summary>
    public class RemoveCacheWithPropertyAttribute : CacheWithPropertyAttribute
    {
        #region Octors
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存Bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="properties">屬性名</param>
        public RemoveCacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
            : base(bucketName, prefix, properties)
        {
        }
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="index">要設置爲緩存的方法參數的索引,索引下標從0開始</param>
        /// <param name="properties">屬性名</param>
        public RemoveCacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
            : base(bucketName, prefix, index, properties)
        {
        }
        #endregion

        #region override
        public override void Called(object resultValue, object[] inputArgs, object[] outputs)
        {
            IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
        }

        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            //IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
            outputs = new object[0];
            return null;
        }
        #endregion
    }
}

 

更新1spa

using MJD.Framework.CrossCutting;
using MJD.Framework.ICache;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 更新緩存特性
    /// </summary>
    public class UpdateCacheAttribute : CacheAttribute
    {
        #region Otors
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        protected UpdateCacheAttribute(string bucketName, string prefix)
            : base(bucketName, prefix)
        {
        }
        /// <summary>
        /// 定義緩存關鍵字來緩存
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="key">緩存鍵</param>
        public UpdateCacheAttribute(string bucketName, string prefix, string key)
            : base(bucketName, prefix, key)
        {
        }

        /// <summary>
        /// 使用當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex">對應的當前參數的緩存鍵所在的參數索引位置</param>
        public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex)
            : base(bucketName, prefix, keyIndex)
        {
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
            : base(bucketName, prefix, keyIndex1, keyIndex2)
        {
        }

        /// <summary>
        /// 使用多個當前參數來緩存,索引位置從0開始
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="keyIndex1">對應的當前參數的緩存鍵所在的參數索引位置1</param>
        /// <param name="keyIndex2">對應的當前參數的緩存鍵所在的參數索引位置2</param>
        /// <param name="keyIndex3">對應的當前參數的緩存鍵所在的參數索引位置3</param>
        public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
            : base(bucketName, prefix, keyIndex1, keyIndex2, keyIndex3)
        {
        }
        #endregion

        #region override
        public override void Called(object resultValue, object[] inputArgs, object[] outputs)
        {
            IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
        }

        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            outputs = new object[0];
            return null;
        }
        #endregion
    }
}

 

更新2code

using MJD.Framework.CrossCutting;
using MJD.Framework.ICache;

namespace MJD.Framework.Aop.Cache
{
    /// <summary>
    /// 更新緩存特性
    /// </summary>
    public class UpdateCacheWithPropertyAttribute : CacheWithPropertyAttribute
    {

        #region Octors
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存Bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="properties">屬性名</param>
        public UpdateCacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
            : base(bucketName, prefix, properties)
        {
        }
        /// <summary>
        /// 根據方法的第一個參數的屬性設置
        /// </summary>
        /// <param name="bucketName">緩存bucket</param>
        /// <param name="prefix">緩存的前綴,避免使用ID做爲緩存鍵時與其餘緩存衝突,必須是獨一無二的前綴</param>
        /// <param name="index">要設置爲緩存的方法參數的索引,索引下標從0開始</param>
        /// <param name="properties">屬性名</param>
        public UpdateCacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
            : base(bucketName, prefix, index, properties)
        {
        }
        #endregion
        
        #region override
        public override void Called(object resultValue, object[] inputArgs, object[] outputs)
        {
            IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
        }

        public override object PreCall(object[] inputArgs, out object[] outputs)
        {
            outputs = new object[0];
            return null;
        }
        #endregion
    }
}
相關文章
相關標籤/搜索