运用Unity结合PolicyInjection实现拦截器[结合操作日志实例]
上一篇文章我们通过Unity自身Unity.InterceptionExtension.IInterceptionBehavior实现一个有系统关异常日志记录;解决代码中到处充满的异常记录的代码;
本文则是通过Unity.InterceptionExtension.ICallHandler实现一个操作日志记录功能;在相应操作方法上通过特性Attribute把操作日志进行统一处理;若想了解Unity依赖注入及AOP功能可以查看先前其它文章;
1:首先我们在公共助手层Command层新建OperateLogCallHandler类及OperateLogAttribute类
其中类OperateLogCallHandler继承自ICallHandler,并且我们定义的属性(MessageInfo,ShowThrow),此处我们只是简单的显示出操作内容信息,若实际项目可以对下面进行简单修改便可,比如写入日志、数据库等;代码result.Exception == null则表示执行代码没有出现异常才逻辑写入
using Microsoft.Practices.Unity.InterceptionExtension; namespace Command { public class OperateLogCallHandler:ICallHandler { public string _messageInfo { set; get; } public bool _showThrow { get; set; } private int _order = 0; public OperateLogCallHandler(string MessageInfo, bool ShowThrow) { this._messageInfo = MessageInfo; this._showThrow = ShowThrow; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { if (input == null) throw new ArgumentNullException("input"); if (getNext == null) throw new ArgumentNullException("getNext"); var result = getNext()(input, getNext); if (result.Exception == null) { //进行逻辑代码编写 比如把操作内容写入数据库 Console.WriteLine("操作的内容为:" + _messageInfo); } if (_showThrow) result.Exception = null; return result; } public int Order { get { return _order; } set { _order = value; } } } }
而类OperateLogAttribute则继承自HandlerAttribute,并且我们设定此特性只能作用于方法上;
using Microsoft.Practices.Unity.InterceptionExtension; namespace Command { [AttributeUsage(AttributeTargets.Method)] public class OperateLogAttribute : HandlerAttribute { public string messageInfo { get; set; } public bool showThrow { get; set; } public OperateLogAttribute() { } public OperateLogAttribute(string MessagInfo, bool ShowThrow) { this.messageInfo = MessagInfo; this.showThrow = ShowThrow; } public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container) { OperateLogCallHandler handler = new OperateLogCallHandler(this.messageInfo, this.showThrow); handler.Order = this.Order; return handler; } } }
2:公共层里还有一个助手类UnityContainerHelp,用于读取加载配置
using Microsoft.Practices.Unity; using Microsoft.Practices.Unity.Configuration; using Microsoft.Practices.Unity.InterceptionExtension; using Microsoft.Practices.Unity.InterceptionExtension.Configuration; using System.Configuration; using System.Reflection; namespace Command { public class UnityContainerHelp { private IUnityContainer container; public UnityContainerHelp() { container = new UnityContainer(); UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); container.LoadConfiguration(section, "FirstClass"); } public T GetServer<T>() { return container.Resolve<T>(); } /// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ConfigName">配置文件中指定的文字</param> /// <returns></returns> public T GetServer<T>(string ConfigName) { return container.Resolve<T>(ConfigName); } /// <summary> /// 返回构结函数带参数 /// </summary> /// <typeparam name="T">依赖对象</typeparam> /// <param name="parameterList">参数集合(参数名,参数值)</param> /// <returns></returns> public T GetServer<T>(Dictionary<string, object> parameterList) { var list = new ParameterOverrides(); foreach (KeyValuePair<string, object> item in parameterList) { list.Add(item.Key, item.Value); } return container.Resolve<T>(list); } /// <summary> /// 返回构结函数带参数 /// </summary> /// <typeparam name="T">依赖对象</typeparam> /// <param name="ConfigName">配置文件中指定的文字(没写会报异常)</param> /// <param name="parameterList">参数集合(参数名,参数值)</param> /// <returns></returns> public T GetServer<T>(string ConfigName,Dictionary<string,object> parameterList) { var list = new ParameterOverrides(); foreach (KeyValuePair<string, object> item in parameterList) { list.Add(item.Key, item.Value); } return container.Resolve<T>(ConfigName,list); } } }
3:接着在接口层相应的方法上使用我们刚才创建的特性,注意必需引用Microsoft.Practices.Unity.InterceptionExtension.dll;若则特性将会找不到
using Microsoft.Practices.Unity.InterceptionExtension; using Command; namespace IAopBLL { public interface IUser { [OperateLog(Order = 10, messageInfo = "增加用户", showThrow = true)] void CreateUser(); [OperateLog(Order = 10, messageInfo = "编辑用户", showThrow = true)] void UpdateUser(); } }
4:在BLL层里实现上面的接口,在方法里面我们就不进行任何操作
using IAopDAL; using IAopBLL; using Command; namespace AopBLL { public class UserBLL:IUser { public void CreateUser() { //逻辑代码,此处为了简单就省略不写 } public void UpdateUser() { //逻辑代码,此处为了简单就省略不写 } } }
5:下面为主程序调用代码,这里我们简单运用到Unity依赖注入代码
using IAopBLL; using Command; namespace AopUnity { class Program { static void Main(string[] args) { Console.WriteLine("-----------------------------------"); IUser bllProperty = new UnityContainerHelp().GetServer<IUser>("UserBllAop"); bllProperty.CreateUser(); bllProperty.UpdateUser(); Console.WriteLine("-----------------------------------"); } } }
配置文件的内容如下:其中有两个比较要注意的地方(a处 name="UserBllAop" 主程序里有调用 b处 <policyInjection/>拦载器才会起作用)
<?xml version="1.0"?> <configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practces/2010/unity"> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/> <container name="FirstClass"> <extension type="Interception"/> <register type="IAopBLL.IUser,IAopBLL" mapTo="AopBLL.UserBLL,AopBLL" name="UserBllAop"> <interceptor type="InterfaceInterceptor" /> <policyInjection/> </register> </container> </unity> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
6:运行效果:
从图中我们不难发现Aop已起到作用,在操作没有异常的情况下我们成功获得操作内容;当然其它Aop比如权限判断,事务处理等都可以用此种办法;