基于PostSharp的AOP框架设计 .

上一篇 / 下一篇  2012-09-12 09:20:13 / 个人分类:阅读整理

  1. AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。   
  2.   
  3. 在Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。   
  4.   
  5. 前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;   
  6.   
  7. 早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhen的PostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:   
  8.   
  9. 和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。   
  10.   
  11. 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。   
  12. 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。   
  13. 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。   
  14. 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。   
  15. 还可以拦截 Field Access、Exception 等操作。   
  16. 无需将对象创建代码改成 "new proxy()",更加透明。   
  17. 可以使用通配符进行多重拦截匹配。   
  18. 静态注入带来的问题更多的是注入代码的质量和调试复杂度。   
  19. 另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。   
  20.   
  21. 我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;   
  22.   
  23. 按以前的写法我们可能很麻烦,我们要如此这般的写:   
  24.   
  25. public class XOrders  
  26.     {  
  27.         public bool Add(string id, string orderName)  
  28.         {  
  29.             try  
  30.             {  
  31.                 if (User.AddEnable)  
  32.                 {  
  33.                     //TODO:新增订单的实现  
  34.                     Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
  35.                     Console.ReadLine();  
  36.                     Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
  37.                     return true;  
  38.                 }  
  39.                 else  
  40.                 {  
  41.                     //  
  42.                 }  
  43.             }  
  44.             catch (Exception)  
  45.             {  
  46.                 //TODO:记录异常的实现  
  47.                 throw;  
  48.             }   
  49.   
  50.             return true;   
  51.   
  52.         }   
  53.   
  54.         public bool Delete(string id)  
  55.         {  
  56.             try  
  57.             {  
  58.                 if (User.DeleteEnable)  
  59.                 {  
  60.                     //TODO:删除订单的实现  
  61.                     Console.WriteLine("您删除订单成功:编号:{0}", id);  
  62.                 }  
  63.                 else  
  64.                 {  
  65.                     //  
  66.                 }   
  67.   
  68.             }  
  69.             catch (Exception)  
  70.             {  
  71.                 //TODO:记录异常的实现  
  72.                 throw;  
  73.             }   
  74.   
  75.             return true;  
  76.         }   
  77.   
  78. 这种写的弊端我就不多说了,有很多先驱都阐述过……   
  79.   
  80. 我要演示的是采用AOP技术的框架原型实现:   
  81.   
  82. 首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)   
  83.   
  84. 然后我们实现Orders对象   
  85.   
  86. using System;   
  87.   
  88. namespace PostSharp.Demo  
  89. {  
  90.     public class Orders  
  91.     {  
  92.         [Permission]  
  93.         [Exception]  
  94.         public bool Add(string id, string orderName)  
  95.         {  
  96.             Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
  97.             Console.ReadLine();  
  98.             Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
  99.             return true;  
  100.         }   
  101.   
  102.         [Logger]  
  103.         [Permission]  
  104.         [Exception]  
  105.         public bool Delete(string id)  
  106.         {  
  107.             Console.WriteLine("您删除订单成功:编号:{0}", id);   
  108.   
  109.             return true;  
  110.         }  
  111.     }  
  112. }   
  113.   
  114. 当然还要模拟一个用户资格认证   
  115.   
  116. namespace PostSharp.Demo  
  117. {  
  118.     /// <summary>  
  119.     /// 静态的用户对象,用于存放当前登录用户,成员资格  
  120.     /// </summary>  
  121.     public static class User  
  122.     {  
  123.         private static string _userId;   
  124.   
  125.         public static string UserId  
  126.         {  
  127.             get { return _userId; }  
  128.             set { _userId = value; }  
  129.         }   
  130.   
  131.         public static bool AddEnable  
  132.         {  
  133.             get  
  134.             {  
  135.                 return (_userId.ToLower() == "admin");  
  136.             }  
  137.         }   
  138.   
  139.         public static bool DeleteEnable  
  140.         {  
  141.             get  
  142.             {  
  143.                 return (_userId.ToLower() == "admin");  
  144.             }  
  145.         }  
  146.     }  
  147. }   
  148.   
  149. 再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……   
  150.   
  151. PermissionAttribute   
  152.   
  153. using System;  
  154. using PostSharp.Laos;   
  155.   
  156. namespace PostSharp.Demo  
  157. {  
  158.     [Serializable]  
  159.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
  160.     public class PermissionAttribute : OnMethodBoundaryAspect  
  161.     {  
  162.         public override void OnEntry(MethodExecutionEventArgs eventArgs)  
  163.         {  
  164.             if (!User.AddEnable)  
  165.             {  
  166.                 Console.WriteLine("用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);  
  167.                 eventArgs.FlowBehavior = FlowBehavior.Return;  
  168.             }   
  169.   
  170.         }  
  171.     }  
  172. }   
  173.   
  174. LoggerAttribute   
  175.   
  176. using System;  
  177. using PostSharp.Laos;   
  178.   
  179. namespace PostSharp.Demo  
  180. {  
  181.     [Serializable]  
  182.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
  183.     public sealed class LoggerAttribute : OnMethodInvocationAspect  
  184.     {  
  185.         public override void OnInvocation(MethodInvocationEventArgs eventArgs)  
  186.         {  
  187.             DateTime time = DateTime.Now;  
  188.             string log = "时间:{0},操作人员:{1},操作:{2}!";   
  189.   
  190.             object[] arg = eventArgs.GetArguments();   
  191.   
  192.             log = String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!");   
  193.   
  194.             System.IO.File.WriteAllText("C://Log.Txt", log);  
  195.         }  
  196.     }  
  197. }   
  198.   
  199. ExceptionAttribute   
  200.   
  201. using System;  
  202. using PostSharp.Laos;   
  203.   
  204. namespace PostSharp.Demo  
  205. {  
  206.     [Serializable]  
  207.     [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]  
  208.     public class ExceptionAttribute : OnExceptionAspect  
  209.     {  
  210.         public override void OnException(MethodExecutionEventArgs eventArgs)  
  211.         {  
  212.             Console.WriteLine("程序出现异常:{0}", eventArgs.Exception.Message);  
  213.             eventArgs.FlowBehavior = FlowBehavior.Return;  
  214.         }  
  215.     }  
  216. }   
  217.   
  218.     
  219.   
  220. 然后再用控制台程序测试下能不能成功   
  221.   
  222. Orders order = new Orders();  
  223.             Console.WriteLine("请输入用户名:");  
  224.             User.UserId = Console.ReadLine();  
  225.             Console.WriteLine("请输入密码:");  
  226.             Console.ReadLine();  
  227.             string id;   
  228.   
  229.             LRedo:  
  230.             Console.WriteLine("请输入您要执行的操作:新增(A),删除(D),退出(X)");   
  231.   
  232.             string opt = Console.ReadLine();   
  233.   
  234.             if (opt.ToLower() == "a")  
  235.             {  
  236.                 Console.WriteLine("请输入订单编号:");  
  237.                 id = Console.ReadLine();   
  238.   
  239.                 Console.WriteLine("请输入订单名称:");  
  240.                 string name = Console.ReadLine();  
  241.                 order.Add(id, name);  
  242.             }  
  243.             else if (opt.ToLower() == "d")  
  244.             {  
  245.                 Console.WriteLine("请输入订单编号:");  
  246.                 id = Console.ReadLine();  
  247.                 order.Delete(id);  
  248.             }  
  249.             else if (opt.ToLower() == "x")  
  250.             {  
  251.             }  
  252.             else  
  253.             {  
  254.                 Console.WriteLine("您的输入不正确,请重新输入!");  
  255.                 goto LRedo;  
  256.             }   
  257.   
  258.             Console.WriteLine("按任意键退出……");  
  259.             Console.ReadLine();   
  260.   
  261. 写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?   
  262.   
  263. public class Orders  
  264. {  
  265.     // Methods  
  266.     static Orders()  
  267.     {  
  268.         if (!~PostSharp~Laos~Implementation.initialized)  
  269.         {  
  270.             LaosNotInitializedException.Throw();  
  271.         }  
  272.         ~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);  
  273.         ~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);  
  274.         ~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);  
  275.         ~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);  
  276.         ~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);  
  277.         ~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);  
  278.         ~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);  
  279.         ~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);  
  280.         ~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);  
  281.         ~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);  
  282.     }   
  283.   
  284.     private bool ~Delete(string id)  
  285.     {  
  286.         Console.WriteLine("您删除订单成功:编号:{0}", id);  
  287.         return true;  
  288.     }   
  289.   
  290.     public bool Add(string id, string orderName)  
  291.     {  
  292.         bool ~returnValue~1;  
  293.         MethodExecutionEventArgs ~laosEventArgs~7;  
  294.         try  
  295.         {  
  296.             object[] ~arguments~6 = new object[] { id, orderName };  
  297.             ~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~6);  
  298.             ~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);  
  299.             if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)  
  300.             {  
  301.                 return (bool) ~laosEventArgs~7.ReturnValue;  
  302.             }  
  303.             try  
  304.             {  
  305.                 Console.WriteLine("正在执行新增订单方法的操作,回车继续……");  
  306.                 Console.ReadLine();  
  307.                 Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);  
  308.                 ~returnValue~1 = true;  
  309.             }  
  310.             catch (Exception ~exception~2)  
  311.             {  
  312.                 object[] ~arguments~3 = new object[] { id, orderName };  
  313.                 MethodExecutionEventArgs ~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~3);  
  314.                 ~laosEventArgs~4.Exception = ~exception~2;  
  315.                 ~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);  
  316.                 switch (~laosEventArgs~4.FlowBehavior)  
  317.                 {  
  318.                     case FlowBehavior.Continue:  
  319.                         goto Label_0145;   
  320.   
  321.                     case FlowBehavior.Return:  
  322.                         ~returnValue~1 = (bool) ~laosEventArgs~4.ReturnValue;  
  323.                         goto Label_0145;  
  324.                 }  
  325.                 throw;  
  326.             }  
  327.         Label_0145:  
  328.             ~laosEventArgs~7.ReturnValue = ~returnValue~1;  
  329.             ~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);  
  330.             ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;  
  331.         }  
  332.         catch (Exception ~exception~5)  
  333.         {  
  334.             ~laosEventArgs~7.Exception = ~exception~5;  
  335.             ~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);  
  336.             switch (~laosEventArgs~7.FlowBehavior)  
  337.             {  
  338.                 case FlowBehavior.Continue:  
  339.                     return ~returnValue~1;   
  340.   
  341.                 case FlowBehavior.Return:  
  342.                     return (bool) ~laosEventArgs~7.ReturnValue;  
  343.             }  
  344.             throw;  
  345.         }  
  346.         finally  
  347.         {  
  348.             ~laosEventArgs~7.ReturnValue = ~returnValue~1;  
  349.             ~PostSharp~Laos~Implementation.~aspect~1.OnExit(~laosEventArgs~7);  
  350.             ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;  
  351.         }  
  352.         return ~returnValue~1;  
  353.     }   
  354.   
  355.     [DebuggerNonUserCode]  
  356.     public bool Delete(string id)  
  357.     {  
  358.         bool ~returnValue~2;  
  359.         MethodExecutionEventArgs ~laosEventArgs~8;  
  360.         try  
  361.         {  
  362.             object[] ~arguments~7 = new object[] { id };  
  363.             ~laosEventArgs~8 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~7);  
  364.             ~PostSharp~Laos~Implementation.~aspect~2.OnEntry(~laosEventArgs~8);  
  365.             if (~laosEventArgs~8.FlowBehavior == FlowBehavior.Return)  
  366.             {  
  367.                 return (bool) ~laosEventArgs~8.ReturnValue;  
  368.             }  
  369.             try  
  370.             {  
  371.                 Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Delete);  
  372.                 object[] arguments = new object[] { id };  
  373.                 MethodInvocationEventArgs eventArgs = new MethodInvocationEventArgs(delegateInstance, arguments);  
  374.                 ~PostSharp~Laos~Implementation.~aspect~5.OnInvocation(eventArgs);  
  375.                 ~returnValue~2 = (bool) eventArgs.ReturnValue;  
  376.             }  
  377.             catch (Exception ~exception~3)  
  378.             {  
  379.                 object[] ~arguments~4 = new object[] { id };  
  380.                 MethodExecutionEventArgs ~laosEventArgs~5 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~4);  
  381.                 ~laosEventArgs~5.Exception = ~exception~3;  
  382.                 ~PostSharp~Laos~Implementation.~aspect~4.OnException(~laosEventArgs~5);  
  383.                 switch (~laosEventArgs~5.FlowBehavior)  
  384.                 {  
  385.                     case FlowBehavior.Continue:  
  386.                         goto Label_0160;   
  387.   
  388.                     case FlowBehavior.Return:  
  389.                         ~returnValue~2 = (bool) ~laosEventArgs~5.ReturnValue;  
  390.                         goto Label_0160;  
  391.                 }  
  392.                 throw;  
  393.             }  
  394.         Label_0160:  
  395.             ~laosEventArgs~8.ReturnValue = ~returnValue~2;  
  396.             ~PostSharp~Laos~Implementation.~aspect~2.OnSuccess(~laosEventArgs~8);  
  397.             ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;  
  398.         }  
  399.         catch (Exception ~exception~6)  
  400.         {  
  401.             ~laosEventArgs~8.Exception = ~exception~6;  
  402.             ~PostSharp~Laos~Implementation.~aspect~2.OnException(~laosEventArgs~8);  
  403.             switch (~laosEventArgs~8.FlowBehavior)  
  404.             {  
  405.                 case FlowBehavior.Continue:  
  406.                     return ~returnValue~2;   
  407.   
  408.                 case FlowBehavior.Return:  
  409.                     return (bool) ~laosEventArgs~8.ReturnValue;  
  410.             }  
  411.             throw;  
  412.         }  
  413.         finally  
  414.         {  
  415.             ~laosEventArgs~8.ReturnValue = ~returnValue~2;  
  416.             ~PostSharp~Laos~Implementation.~aspect~2.OnExit(~laosEventArgs~8);  
  417.             ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;  
  418.         }  
  419.         return ~returnValue~2;  
  420.     }  
  421. }   

TAG:

 

评分:0

我来说两句

Open Toolbar