先下载这个NUGET包。
个人理解UINITY是在IOC上实现的AOP(自己试验了好多次),所以先定义接口跟实现类。
namespace Cache { public class Talk : ITalk { [Caching(CachingMethod.Get)] public System.Collections.Generic.List<string> GetData() { Data.UpData(); return Data.GetData(); } } } namespace Cache { public interface ITalk { [Caching(CachingMethod.Get)] List<string> GetData(); } }
然后写CachingAttribute特性类。实际上所有ITalk的实现都会被拦截,所以写了一个特性来筛选。
[AttributeUsage(AttributeTargets.Method,AllowMultiple = false,Inherited = false)] public class CachingAttribute:Attribute { /// <summary> /// 初始化一个新的<c>CachingAttribute</c>类型。 /// </summary> /// <param name="method">缓存方式。</param> public CachingAttribute(CachingMethod method) { Method = method; } /// <summary> /// 初始化一个新的<c>CachingAttribute</c>类型。 /// </summary> /// <param name="method">缓存方式。</param> /// <param name="correspondingMethodNames"> /// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 /// </param> public CachingAttribute(CachingMethod method, params string[] correspondingMethodNames) : this(method) { CorrespondingMethodNames = correspondingMethodNames; } #region Public Properties /// <summary> /// 获取或设置缓存方式。 /// </summary> public CachingMethod Method { get; set; } /// <summary> /// 获取或设置一个<see cref="Boolean"/>值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。 /// </summary> public bool Force { get; set; } /// <summary> /// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 /// </summary> public string[] CorrespondingMethodNames { get; set; } #endregion }
枚举
public enum CachingMethod { Get, Put, Remove }
CachingMethod
缓存机制接口
/// <summary> /// 表示实现该接口的类型是能够为应用程序提供缓存机制的类型。 /// </summary> public interface ICacheProvider { #region Methods /// <summary> /// 向缓存中添加一个对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <param name="value">需要缓存的对象。</param> void Add(string key, string valKey, object value); /// <summary> /// 向缓存中更新一个对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <param name="value">需要缓存的对象。</param> void Put(string key, string valKey, object value); /// <summary> /// 从缓存中读取对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <returns>被缓存的对象。</returns> object Get(string key, string valKey); /// <summary> /// 从缓存中移除对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> void Remove(string key); /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值的缓存是否存在。 /// </summary> /// <param name="key">指定的键值。</param> /// <returns>如果缓存存在,则返回true,否则返回false。</returns> bool Exists(string key); /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值和缓存值键的缓存是否存在。 /// </summary> /// <param name="key">指定的键值。</param> /// <param name="valKey">缓存值键。</param> /// <returns>如果缓存存在,则返回true,否则返回false。</returns> bool Exists(string key, string valKey); #endregion }
ICacheProvider
两种方式的缓存接口实现
/// <summary> /// 表示基于AppFabric的缓存机制的实现。 /// </summary> public class AppfabricCacheProvider : ICacheProvider { private readonly DataCacheFactory factory = new DataCacheFactory(); private readonly DataCache cache; public AppfabricCacheProvider() { cache = factory.GetDefaultCache(); } #region ICacheProvider Members public void Add(string key, string valKey, object value) { Dictionary<string, object> val = (Dictionary<string, object>)cache.Get(key); if (val == null) { val = new Dictionary<string, object>(); val.Add(valKey, value); cache.Add(key, val); } else { if (!val.ContainsKey(valKey)) val.Add(valKey, value); else val[valKey] = value; cache.Put(key, val); } } public void Put(string key, string valKey, object value) { Add(key, valKey, value); } public object Get(string key, string valKey) { if (Exists(key, valKey)) { return ((Dictionary<string, object>)cache.Get(key))[valKey]; } return null; } public void Remove(string key) { cache.Remove(key); } public bool Exists(string key) { return cache.Get(key) != null; } public bool Exists(string key, string valKey) { var val = cache.Get(key); if (val == null) return false; return ((Dictionary<string, object>)val).ContainsKey(valKey); } #endregion }
AppfabricCacheProvider
/// <summary> /// 表示基于Microsoft Patterns & Practices - Enterprise Library Caching Application Block的缓存机制的实现。 /// </summary> public class EntLibCacheProvider : ICacheProvider { #region Private Fields private readonly ICacheManager cacheManager = CacheFactory.GetCacheManager(); #endregion #region ICacheProvider Members /// <summary> /// 向缓存中添加一个对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <param name="value">需要缓存的对象。</param> public void Add(string key, string valKey, object value) { Dictionary<string, object> dict = null; if (cacheManager.Contains(key)) { dict = (Dictionary<string, object>)cacheManager[key]; dict[valKey] = value; } else { dict = new Dictionary<string, object>(); dict.Add(valKey, value); } cacheManager.Add(key, dict); } /// <summary> /// 向缓存中更新一个对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <param name="value">需要缓存的对象。</param> public void Put(string key, string valKey, object value) { Add(key, valKey, value); } /// <summary> /// 从缓存中读取对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param> /// <returns>被缓存的对象。</returns> public object Get(string key, string valKey) { if (cacheManager.Contains(key)) { Dictionary<string, object> dict = (Dictionary<string, object>)cacheManager[key]; if (dict != null && dict.ContainsKey(valKey)) return dict[valKey]; else return null; } return null; } /// <summary> /// 从缓存中移除对象。 /// </summary> /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param> public void Remove(string key) { cacheManager.Remove(key); } /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值的缓存是否存在。 /// </summary> /// <param name="key">指定的键值。</param> /// <returns>如果缓存存在,则返回true,否则返回false。</returns> public bool Exists(string key) { return cacheManager.Contains(key); } /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值和缓存值键的缓存是否存在。 /// </summary> /// <param name="key">指定的键值。</param> /// <param name="valKey">缓存值键。</param> /// <returns>如果缓存存在,则返回true,否则返回false。</returns> public bool Exists(string key, string valKey) { return cacheManager.Contains(key) && ((Dictionary<string, object>)cacheManager[key]).ContainsKey(valKey); } #endregion }
EntLibCacheProvider
CacheManager用来管理缓存实现( public ICacheProvider CacheProvider = new EntLibCacheProvider();这里可以应该用依赖注入,因为测试懒得写了就直接实例化了)
public class CacheManager : ICacheProvider { public ICacheProvider CacheProvider = new EntLibCacheProvider(); // ReSharper disable once InconsistentNaming private CacheManager instance = new CacheManager(); static CacheManager() { } #region 公共属性 /// <summary> /// 获取<c>CacheManager</c>类型的单件(Singleton)实例。 /// </summary> public CacheManager Instance { get { return instance; } } #endregion public void Add(string key, string valKey, object value) { CacheProvider.Add(key, valKey, value); } public void Put(string key, string valKey, object value) { CacheProvider.Put(key, valKey, value); } public object Get(string key, string valKey) { return CacheProvider.Get(key, valKey); } public void Remove(string key) { CacheProvider.Remove(key); } public bool Exists(string key) { return CacheProvider.Exists(key); } public bool Exists(string key, string valKey) { return CacheProvider.Exists(key, valKey); } }
CacheManager
AOP拦截。getNext().Invoke(input, getNext)这一句相当于获取被拦截方法的返回值
public class CachingBehavior : IInterceptionBehavior { /// <summary> /// 根据指定的<see cref="CachingAttribute"/>以及<see cref="IMethodInvocation"/>实例, /// 获取与某一特定参数值相关的键名。 /// </summary> /// <param name="cachingAttribute"><see cref="CachingAttribute"/>实例。</param> /// <param name="input"><see cref="IMethodInvocation"/>实例。</param> /// <returns>与某一特定参数值相关的键名。 /// <remarks> /// 例如:<see cref="ICacheProvider.Add"/> /// </remarks> /// </returns> private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input) { switch (cachingAttribute.Method) { case CachingMethod.Remove: return null; case CachingMethod.Get: case CachingMethod.Put: if (input.Arguments != null && input.Arguments.Count > 0) { var sb = new StringBuilder(); for (int i = 0; i < input.Arguments.Count; i++) { sb.Append(input.Arguments[i].ToString()); if (i != input.Arguments.Count - 1) sb.Append("_"); } return sb.ToString(); } else { return "Null"; } default: throw new InvalidOperationException("无效的缓存方式。"); } } /// <summary> /// 获取当前行为需要拦截的对象类型接口。 /// </summary> /// <returns>所有需要拦截的对象类型接口。</returns> public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } /// <summary> /// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// </summary> /// <param name="input">调用拦截目标时的输入信息。</param> /// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param> /// <returns>从拦截目标获得的返回信息。</returns> public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { var method = input.MethodBase; var key = method.Name; if (method.IsDefined(typeof(CachingAttribute), false)) { var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[0]; var valKey = GetValueKey(cachingAttribute, input); switch (cachingAttribute.Method) { case CachingMethod.Get: //try { if (new CacheManager().Instance.Exists(key, valKey)) { var obj = new CacheManager().Instance.Get(key, valKey); var arguments = new object[input.Arguments.Count]; input.Arguments.CopyTo(arguments, 0); return new VirtualMethodReturn(input, obj, arguments); } var methodReturn = getNext().Invoke(input, getNext); if (methodReturn.Exception == null) { new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue); } return methodReturn; } //catch (Exception ex) //{ // return new VirtualMethodReturn(input, ex); //} case CachingMethod.Put: try { var methodReturn = getNext().Invoke(input, getNext); if (new CacheManager().Instance.Exists(key)) { if (cachingAttribute.Force) { new CacheManager().Instance.Remove(key); new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue); } else new CacheManager().Instance.Put(key, valKey, methodReturn.ReturnValue); } else new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } case CachingMethod.Remove: try { var removeKeys = cachingAttribute.CorrespondingMethodNames; foreach (var removeKey in removeKeys) { if (new CacheManager().Instance.Exists(removeKey)) new CacheManager().Instance.Remove(removeKey); } var methodReturn = getNext().Invoke(input, getNext); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } } } return getNext().Invoke(input, getNext); } /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行 /// 某些操作。 /// </summary> public bool WillExecute { get { return true; } } }
CachingBehavior
Unity操作类
/// <summary> /// Represents the Service Locator. /// </summary> public sealed class ServiceLocator : IServiceProvider { #region Private Fields private readonly IUnityContainer container; #endregion #region Private Static Fields private static readonly ServiceLocator instance = new ServiceLocator(); #endregion #region Ctor /// <summary> /// Initializes a new instance of <c>ServiceLocator</c> class. /// </summary> private ServiceLocator() { UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); container = new UnityContainer(); section.Configure(container); } #endregion #region Public Static Properties /// <summary> /// Gets the singleton instance of the <c>ServiceLocator</c> class. /// </summary> public static ServiceLocator Instance { get { return instance; } } #endregion #region Private Methods private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments) { List<ParameterOverride> overrides = new List<ParameterOverride>(); Type argumentsType = overridedArguments.GetType(); argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToList() .ForEach(property => { var propertyValue = property.GetValue(overridedArguments, null); var propertyName = property.Name; overrides.Add(new ParameterOverride(propertyName, propertyValue)); }); return overrides; } #endregion #region Public Methods /// <summary> /// Gets the service instance with the given type. /// </summary> /// <typeparam name="T">The type of the service.</typeparam> /// <returns>The service instance.</returns> public T GetService<T>() { return container.Resolve<T>(); } /// <summary> /// Gets the service instance with the given type by using the overrided arguments. /// </summary> /// <typeparam name="T">The type of the service.</typeparam> /// <param name="overridedArguments">The overrided arguments.</param> /// <returns>The service instance.</returns> public T GetService<T>(object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return container.Resolve<T>(overrides.ToArray()); } /// <summary> /// Gets the service instance with the given type by using the overrided arguments. /// </summary> /// <param name="serviceType">The type of the service.</param> /// <param name="overridedArguments">The overrided arguments.</param> /// <returns>The service instance.</returns> public object GetService(Type serviceType, object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return container.Resolve(serviceType, overrides.ToArray()); } #endregion #region IServiceProvider Members /// <summary> /// Gets the service instance with the given type. /// </summary> /// <param name="serviceType">The type of the service.</param> /// <returns>The service instance.</returns> public object GetService(Type serviceType) { return container.Resolve(serviceType); } #endregion }
ServiceLocator
最后需要在配置文件中配置一下。
<configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> </configSections> <!--BEGIN: Unity--> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <container> <extension type="Interception" /> <!--Cache Provider--> <register type="Cache.ITalk, Cache" mapTo="Cache.Talk, Cache"> <interceptor type="InterfaceInterceptor" /> <interceptionBehavior type="Cache.CachingBehavior, Cache" /> </register> </container> </unity> <!--END: Unity-->
WebConfig
https://github.com/dxka8/AopWeb 代码
经测试AOP已经实现,但是两个缓存实现因为用的第三方还在报错(自己实现一个也可),正在踏坑(有懂的同学可以支援一下我啊)。
注明:非原创,在dax.net的APWORKS里面扒的。
时间: 2024-10-13 12:50:39