输入参数索引做为缓存键的实现缓存
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 } }