第一步:定义拦截行为:CachingBehavior 和 ExceptionLoggingBehavior
他们都继承接口:IInterceptionBehavior (程序集 Microsoft.Practices.Unity.Interception.dll, v2.1.505.0
命名空间:Microsoft.Practices.Unity.InterceptionExtension)
需要实现连个接口:
public IEnumerableGetRequiredInterfaces()public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
CachingBehavior.cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Keasy5.Infrastructure.Caching;using Microsoft.Practices.Unity.InterceptionExtension;namespace Keasy5.Infrastructure.InterceptionBehaviors{ ////// 表示用于方法缓存功能的拦截行为。 /// public class CachingBehavior : IInterceptionBehavior { #region Private Methods ////// 根据指定的 ///以及 实例, /// 获取与某一特定参数值相关的键名。 /// 实例。 /// 实例。 /// 与某一特定参数值相关的键名。 /// private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input) { switch (cachingAttribute.Method) { // 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除 case CachingMethod.Remove: return null; // 如果是Get或者Put,则需要产生一个针对特定参数值的键名 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("无效的缓存方式。"); } } #endregion #region IInterceptionBehavior Members ////// 例如: ////// /// 获取当前行为需要拦截的对象类型接口。 /// ///所有需要拦截的对象类型接口。 public IEnumerableGetRequiredInterfaces() { return Type.EmptyTypes; } /// /// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// /// 调用拦截目标时的输入信息。 /// 通过行为链来获取下一个拦截行为的委托。 ///从拦截目标获得的返回信息。 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 (CacheManager.Instance.Exists(key, valKey)) { var obj = CacheManager.Instance.Get(key, valKey); var arguments = new object[input.Arguments.Count]; input.Arguments.CopyTo(arguments, 0); return new VirtualMethodReturn(input, obj, arguments); } else { var methodReturn = getNext().Invoke(input, getNext); 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 (CacheManager.Instance.Exists(key)) { if (cachingAttribute.Force) { CacheManager.Instance.Remove(key); CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue); } else CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue); } else 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 (CacheManager.Instance.Exists(removeKey)) CacheManager.Instance.Remove(removeKey); } var methodReturn = getNext().Invoke(input, getNext); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } default: break; } } return getNext().Invoke(input, getNext); } ////// 获取一个 public bool WillExecute { get { return true; } } #endregion }}值,该值表示当前拦截行为被调用时,是否真的需要执行 /// 某些操作。 ///
ExceptionLoggingBehavior.cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using Microsoft.Practices.Unity.InterceptionExtension;namespace Keasy5.Infrastructure.InterceptionBehaviors{ ////// 表示用于异常日志记录的拦截行为。 /// public class ExceptionLoggingBehavior : IInterceptionBehavior { #region IInterceptionBehavior Members ////// 获取当前行为需要拦截的对象类型接口。 /// ///所有需要拦截的对象类型接口。 public IEnumerableGetRequiredInterfaces() { return Type.EmptyTypes; } /// /// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// /// 调用拦截目标时的输入信息。 /// 通过行为链来获取下一个拦截行为的委托。 ///从拦截目标获得的返回信息。 public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { var methodReturn = getNext().Invoke(input, getNext); if (methodReturn.Exception != null) { Utils.Log(methodReturn.Exception); } return methodReturn; } ////// 获取一个 public bool WillExecute { get { return true; } } #endregion }}值,该值表示当前拦截行为被调用时,是否真的需要执行 /// 某些操作。 ///
第二步:添加配置文件,为需要被拦截的类添加拦截行为。
例如如下的配置,是为实现了接口
Keasy5.ServiceContract.IProductService
的类的所以方法添加拦截行为。
web/app.config文件:
。。。。。 。。。。
比如:对于ExceptionLoggingBehavior的拦截行为作用于IProductService接口的实现类的所有方法:
////// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// /// 调用拦截目标时的输入信息。 /// 通过行为链来获取下一个拦截行为的委托。 ///从拦截目标获得的返回信息。 public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { var methodReturn = getNext().Invoke(input, getNext); if (methodReturn.Exception != null) { Utils.Log(methodReturn.Exception); } return methodReturn; }
效果是:如果IProductService接口的实现类的所有方法如果抛出了异常,将调用
Utils.Log(methodReturn.Exception);
将异常信息写入日志系统(这就是我们进行拦截的目的)。
------------------------------------------------
对应缓存CachingBehavior的拦截的补充:
第一:定义特性:CachingAttribute
CachingAttribute.cs
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Keasy5.Infrastructure.Caching{ ////// 表示由此特性所描述的方法,能够获得来自基础结构层所提供的缓存功能。 /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public class CachingAttribute : Attribute { #region Ctor ////// 初始化一个新的 /// 缓存方式。 public CachingAttribute(CachingMethod method) { this.Method = method; } ///CachingAttribute 类型。 ////// 初始化一个新的 /// 缓存方式。 /// /// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 /// public CachingAttribute(CachingMethod method, params string[] correspondingMethodNames) : this(method) { this.CorrespondingMethodNames = correspondingMethodNames; } #endregion #region Public Properties ///CachingAttribute 类型。 ////// 获取或设置缓存方式。 /// public CachingMethod Method { get; set; } ////// 获取或设置一个 public bool Force { get; set; } ///值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。 /// /// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。 /// public string[] CorrespondingMethodNames { get; set; } #endregion }}
第二:将特性CachingAttribute应用于IProductService的接口方法:
using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;using ByteartRetail.DataObjects;using Keasy5.DataObject;using Keasy5.Infrastructure;using Keasy5.Infrastructure.Caching;namespace Keasy5.ServiceContract{ ////// 表示与“商品”相关的应用层服务契约。 /// [ServiceContract(Namespace = "http://www.ByteartRetail.com")] public interface IProductService : IApplicationServiceContract { #region Methods ////// 创建商品信息。 /// /// 需要创建的商品信息。 ///已创建的商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetProductsForCategory", "GetProductsWithPagination", "GetFeaturedProducts", "GetProductsForCategoryWithPagination", "GetProducts", "GetProductByID")] ProductDataObjectList CreateProducts(ProductDataObjectList productDataObjects); ////// 创建商品分类。 /// /// 需要创建的商品分类。 ///已创建的商品分类。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetCategories")] CategoryDataObjectList CreateCategories(CategoryDataObjectList categoryDataObjects); ////// 更新商品信息。 /// /// 需要更新的商品信息。 ///已更新的商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetProductsForCategory", "GetProductsWithPagination", "GetFeaturedProducts", "GetProductsForCategoryWithPagination", "GetProducts", "GetProductByID")] ProductDataObjectList UpdateProducts(ProductDataObjectList productDataObjects); ////// 更新商品分类。 /// /// 需要更新的商品分类。 ///已更新的商品分类。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")] CategoryDataObjectList UpdateCategories(CategoryDataObjectList categoryDataObjects); ////// 删除商品信息。 /// /// 需要删除的商品信息的ID值。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetProductsForCategory", "GetProductsWithPagination", "GetFeaturedProducts", "GetProductsForCategoryWithPagination", "GetProducts", "GetProductByID")] void DeleteProducts(IDList productIDs); ////// 删除商品分类。 /// /// 需要删除的商品分类的ID值。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetCategories", "GetCategoryByID")] void DeleteCategories(IDList categoryIDs); ////// 设置商品分类。 /// /// 需要进行分类的商品ID值。 /// 商品分类ID值。 ///带有商品分类信息的对象。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetProductsForCategory", "GetProductsForCategoryWithPagination")] CategorizationDataObject CategorizeProduct(Guid productID, Guid categoryID); ////// 取消商品分类。 /// /// 需要取消分类的商品ID值。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Remove, "GetProductsForCategory", "GetProductsForCategoryWithPagination")] void UncategorizeProduct(Guid productID); ////// 根据指定的ID值获取商品分类。 /// /// 商品分类ID值。 /// 查询方式。 ///商品分类。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] CategoryDataObject GetCategoryByID(Guid id, QuerySpec spec); ////// 获取所有的商品分类。 /// /// 查询方式。 ///所有的商品分类。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] CategoryDataObjectList GetCategories(QuerySpec spec); ////// 根据指定的ID值获取商品信息。 /// /// 商品信息ID值。 /// 查询方式。 ///商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObject GetProductByID(Guid id, QuerySpec spec); ////// 获取所有的商品信息。 /// /// 查询方式。 ///商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObjectList GetProducts(QuerySpec spec); ////// 以分页的方式获取所有商品信息。 /// /// 带有分页参数信息的对象。 ///经过分页的商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObjectListWithPagination GetProductsWithPagination(Pagination pagination); ////// 根据指定的商品分类ID值,获取该分类下所有的商品信息。 /// /// 商品分类ID值。 ///所有的商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObjectList GetProductsForCategory(Guid categoryID); ////// 根据指定的商品分类ID值,以分页的方式获取该分类下所有的商品信息。 /// /// 商品分类ID值。 /// 带有分页参数信息的对象。 ///所有的商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObjectListWithPagination GetProductsForCategoryWithPagination(Guid categoryID, Pagination pagination); ////// 获取所有的特色商品信息。 /// /// 需要获取的特色商品信息的个数。 ///特色商品信息。 [OperationContract] [FaultContract(typeof(FaultData))] [Caching(CachingMethod.Get)] ProductDataObjectList GetFeaturedProducts(int count); #endregion }}
第三:拦截IProductService接口的实现类的所有方法的所有方法,
并通过CachingAttribute特性进行方法 的筛选,
还进一步根据CachingAttribute的属性值进行一步的处理:
CachingBehavior .cs
////// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// /// 调用拦截目标时的输入信息。 /// 通过行为链来获取下一个拦截行为的委托。 ///从拦截目标获得的返回信息。 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 (CacheManager.Instance.Exists(key, valKey)) { var obj = CacheManager.Instance.Get(key, valKey); var arguments = new object[input.Arguments.Count]; input.Arguments.CopyTo(arguments, 0); return new VirtualMethodReturn(input, obj, arguments); } else { var methodReturn = getNext().Invoke(input, getNext); 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 (CacheManager.Instance.Exists(key)) { if (cachingAttribute.Force) { CacheManager.Instance.Remove(key); CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue); } else CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue); } else 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 (CacheManager.Instance.Exists(removeKey)) CacheManager.Instance.Remove(removeKey); } var methodReturn = getNext().Invoke(input, getNext); return methodReturn; } catch (Exception ex) { return new VirtualMethodReturn(input, ex); } default: break; } } return getNext().Invoke(input, getNext); }
--------------------------------
unity服务定位器:ServiceLocator
ServiceLocator.cs
using System;using System.Collections.Generic;using System.Configuration;using System.Linq;using System.Reflection;using System.Text;using Microsoft.Practices.Unity;using Microsoft.Practices.Unity.Configuration;namespace Keasy5.Infrastructure{ ////// Represents the Service Locator. /// 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 ////// Initializes a new instance of private ServiceLocator() { UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); container = new UnityContainer(); section.Configure(container); } #endregion #region Public Static Properties ///ServiceLocator class. ////// Gets the singleton instance of the public static ServiceLocator Instance { get { return instance; } } #endregion #region Private Methods private IEnumerableServiceLocator class. ///GetParameterOverrides(object overridedArguments) { List overrides = new List (); 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 /// /// Gets the service instance with the given type. /// ///The type of the service. ///The service instance. public T GetService() { return container.Resolve (); } public IEnumerable ResolveAll () { return container.ResolveAll (); } /// /// Gets the service instance with the given type by using the overrided arguments. /// ///The type of the service. /// The overrided arguments. ///The service instance. public T GetService(object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return container.Resolve (overrides.ToArray()); } /// /// Gets the service instance with the given type by using the overrided arguments. /// /// The type of the service. /// The overrided arguments. ///The service instance. public object GetService(Type serviceType, object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return container.Resolve(serviceType, overrides.ToArray()); } #endregion #region IServiceProvider Members ////// Gets the service instance with the given type. /// /// The type of the service. ///The service instance. public object GetService(Type serviceType) { return container.Resolve(serviceType); } #endregion }}