在本文之前的前几篇浅谈.NET编译时注入(C#-->IL浅谈VS编译自定义编译任务—MSBuild Task(csproject)编译时MSIL注入--实践Mono Cecil(1)已经讨论了MSBuild和Mono.Cicel。在这里我们将会利用它来实现一个简单的编译时AOP注入机制(这里所说的编译时是指c#到MSIL的预编译过程)。我更倾向于像EL(微软企业库框架)这类动态AOP。编译时AOP有PostSharp这种被称之为静态AOP框架,其优势在于直接代码语句,性能更好,它不需要我们多余的代码,像EL这种动态AOP,一般我们是不能直接new一个对象,需要容器(Container),在一些你的框架应用种,有时就需要使用者了解,再入我们对于WinForm、WebForm等.net平台上主流的基于微软事件机制的框架,事件方法的截获,往往我们需要改变、包装。在这时静态AOP就显出了他的优势。

Class Diagram

1IMethodInjectInterface,拥有ExecuteingExceptionedExecuteSuccess三个契约为别为执行前,异常,成功。它们都有公同的参数类型:MethodExecutionEventArgs

 

Executeing:返回值为bool类型,将决定是否继续执行方法体。Exceptioned:属性Eeption代表发生的异常信息,返回值ExceptionStrategy(取值:Handle, ReThrow, ThrowNew)决定异常处理机制,Handle已处理并忽略,ReThrow重新抛出,ThrowNew抛出一个包装后的来源于MethodExecutionEventArgs 的Exception。ExecuteSuccess,对于拥有返回值的方法,可以修改MethodExecutionEventArgs 的ReturnValue,修改返回值。最后MethodExecutionEventArgs的Order决定多个Attribute的注入先后,即方法截获的先后顺序。

1:MethodInterceptBase针对于方法Attribute标签,实现方法截获View Code

  1. [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]  
  2.     public class MethodInterceptBase : Attribute, IMethodInject  
  3.     {  
  4.         public int Order 
  5.         {  
  6.             get;  
  7.             set;  
  8.         }  
  9.         #region IMethodInject Members  
  10.  
  11.         public virtual bool Executeing(MethodExecutionEventArgs args)  
  12.         {  
  13.             return true;  
  14.         }  
  15.  
  16.         public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)  
  17.         {  
  18.             return ExceptionStrategy.ReThrow;  
  19.         }  
  20.  
  21.         public virtual void ExecuteSuccess(MethodExecutionEventArgs args)  
  22.         {  
  23.  
  24.         }  
  25.          
  26.         #endregion  
  27. }  
  28. 复制代码 

 

2:

MatchedMethodInterceptBase:和上面方法之上的MethodInterceptBase大体一致,区别在于其应用于class之上,属性Rule为截获方法匹配(应用于多个方法之上相同截获),支持*匹配。

 

 

  1. View Code   
  2.    
  3. [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]  
  4.  
  5.     public class MatchedMethodInterceptBase : Attribute, IMethodInject  
  6.  
  7.     {  
  8.  
  9.         public int Order 
  10.  
  11.         {  
  12.  
  13.             get;  
  14.  
  15.             set;  
  16.  
  17.         }  
  18.  
  19.    
  20.  
  21.         public string Rule 
  22.  
  23.         {  
  24.  
  25.             get;  
  26.  
  27.             set;  
  28.  
  29.         }  
  30.  
  31.         #region IMethodInject Members  
  32.  
  33.  
  34.         public virtual bool Executeing(MethodExecutionEventArgs args)  
  35.  
  36.         {  
  37.  
  38.             return true;  
  39.  
  40.         }  
  41.    
  42.  
  43.         public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)  
  44.  
  45.         {  
  46.  
  47.             return ExceptionStrategy.ReThrow;  
  48.  
  49.         }  
  50.  
  51.    
  52.  
  53.         public virtual void ExecuteSuccess(MethodExecutionEventArgs args)  
  54.  
  55.         {  
  56.  
  57.    
  58.  
  59.         }  
  60.  
  61.          
  62.  
  63.         #endregion  
  64.  
  65.     }  
  66. 复制代码 

3PropertyInterceptBase实现属性的注入,其属性Actionenum PropertyInterceptActionNone Get, Set)指注入属性的get或者SetView Code

 
其上默认都是Executeing继续执行,Exceptioned为抛出不处理,成功不修改result。

下面是一个简单测试Code:

  1. View Code   
  2.  
  3. using System;  
  4.  
  5. using System.Collections.Generic;  
  6.  
  7. using System.Linq;  
  8.  
  9. using System.Text;  
  10.  
  11. using System.Reflection;  
  12.  
  13. using Green.AOP;  
  14.  
  15.    
  16.  
  17. namespace Test  
  18.  
  19. {     
  20.  
  21.     // [TestAOP2Attribute(Rule = "TestMethod1*")]  
  22.  
  23.     public class Class1  
  24.  
  25.     {  
  26.  
  27.         // [TestAOPPropertyAttribute(Action = PropertyInterceptAction.Set)]  
  28.  
  29.         [TestAOPPropertyGetAttribute(Action = PropertyInterceptAction.Get)]  
  30.  
  31.         public testStrust TestProperty  
  32.  
  33.         {  
  34.  
  35.             get;  
  36.  
  37.             set;  
  38.  
  39.         }  
  40.  
  41.         [Obsolete()]  
  42.  
  43.         public static void Main(string[] args)  
  44.  
  45.         {            
  46.  
  47.             try  
  48.  
  49.             {  
  50.  
  51.                 var y = new Class1();  
  52.  
  53.                 // y.TestProperty = DateTime.Now;  
  54.  
  55.                 Console.WriteLine(y.TestProperty);  
  56.  
  57.             }  
  58.  
  59.             catch (Exception ex)  
  60.  
  61.             {  
  62.  
  63.                 Console.WriteLine(ex.ToString());  
  64.  
  65.             }  
  66.  
  67.             // new Class1().TestMethod1(1, 2, null);  
  68.  
  69.             Console.Read();  
  70.  
  71.             //throw new Exception("exfffffffffffffffffffff");  
  72.  
  73.         }  
  74.  
  75.         //[TestAOPAttribute(Order=1)]  
  76.  
  77.         //[TestAOP1Attribute(TestProperty = 1, Template = "sdsdsd",Order=0)]  
  78.  
  79.         public Class1 TestMethod1(int i, int j, Class1 c)  
  80.  
  81.         {  
  82.  
  83.             Console.WriteLine("ok");  
  84.  
  85.             return new Class1();  
  86.  
  87.         }  
  88.  
  89.     }  
  90.  
  91.     public class TestAOPPropertyGetAttribute : Green.AOP.PropertyInterceptBase  
  92.  
  93.     {  
  94.  
  95.         #region IMethodInject Members  
  96.  
  97.         public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)  
  98.  
  99.         {  
  100.  
  101.             Console.WriteLine("------------------" + args);  
  102.  
  103.             Console.WriteLine(args.Instance);  
  104.  
  105.             Console.WriteLine(args.Method);  
  106.  
  107.             Console.WriteLine(this.GetType() + ":" + "Executeing");  
  108.  
  109.             return true;  
  110.  
  111.         }  
  112.  
  113.         public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)  
  114.  
  115.         {  
  116.  
  117.             Console.WriteLine(this.GetType() + ":" + "Exceptioned");  
  118.  
  119.             return Green.AOP.ExceptionStrategy.ReThrow;  
  120.  
  121.         }  
  122.  
  123.         public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)  
  124.  
  125.         {  
  126.  
  127.             Console.WriteLine("-----------");  
  128.  
  129.             Console.WriteLine(this.GetType() + ":" + "ExecuteSuccess" + "--result:" + args.ReturnValue);  
  130.  
  131.         }  
  132.  
  133.         #endregion  
  134.  
  135.     }  
  136.  
  137.     public class TestAOPPropertyAttribute : Green.AOP.PropertyInterceptBase  
  138.  
  139.     {  
  140.  
  141.         #region IMethodInject Members  
  142.  
  143.         public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)  
  144.  
  145.         {  
  146.  
  147.             Console.WriteLine(args.Instance);  
  148.  
  149.             Console.WriteLine(args.Method);  
  150.  
  151.             Console.WriteLine(this.GetType() + ":" + "Executeing");  
  152.  
  153.             return true;  
  154.  
  155.         }  
  156.  
  157.         public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)  
  158.  
  159.         {  
  160.  
  161.             Console.WriteLine(this.GetType() + ":" + "Exceptioned");  
  162.  
  163.             return Green.AOP.ExceptionStrategy.Handle;  
  164.  
  165.         }  
  166.  
  167.         public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)  
  168.  
  169.        {  
  170.  
  171.             Console.WriteLine(this.GetType() + ":" + "ExecuteSuccess");  
  172.  
  173.         }  
  174.  
  175.         #endregion  
  176.  
  177.     }  
  178.  
  179.     public class TestAOP2Attribute : Green.AOP.MatchedMethodInterceptBase  
  180.  
  181.     {  
  182.  
  183.         #region IMethodInject Members  
  184.  
  185.         public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)  
  186.  
  187.         {  
  188.  
  189.             Console.WriteLine(args.Instance);  
  190.  
  191.             Console.WriteLine(args.Method);  
  192.  
  193.             Console.WriteLine(this.GetType() + ":" + "Executeing");  
  194.  
  195.             return true;  
  196.  
  197.         }  
  198.  
  199.         public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)  
  200.  
  201.         {  
  202.  
  203.             Console.WriteLine(this.GetType() + ":" + "Exceptioned");  
  204.  
  205.             return Green.AOP.ExceptionStrategy.Handle;  
  206.  
  207.         }  
  208.  
  209.         public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)  
  210.  
  211.         {  
  212.  
  213.             Console.WriteLine(this.GetType() + ":" + "ExecuteSuccess");  
  214.  
  215.         }  
  216.  
  217.         #endregion  
  218.  
  219.         #region IMethodInject Members  
  220.  
  221.         public bool Match(System.Reflection.MethodBase method)  
  222.  
  223.         {  
  224.  
  225.             return true;  
  226.  
  227.         }  
  228.  
  229.         #endregion  
  230.  
  231.     }  
  232.  
  233.    
  234.  
  235.     //[AttributeUsage(AttributeTargets.Method)]  
  236.  
  237.     public class TestAOPAttribute : Green.AOP.MethodInterceptBase  
  238.  
  239.     {  
  240.  
  241.         #region IMethodInject Members  
  242.  
  243.         public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)  
  244.  
  245.         {  
  246.  
  247.             Console.WriteLine(this.GetType() + ":" + "Executeing");  
  248.  
  249.             return true;  
  250.  
  251.         }  
  252.  
  253.    
  254.  
  255.         public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)  
  256.  
  257.         {  
  258.  
  259.             Console.WriteLine(this.GetType() + ":" + "Exceptioned");  
  260.  
  261.             return Green.AOP.ExceptionStrategy.Handle;  
  262.  
  263.         }  
  264.  
  265.    
  266.  
  267.         public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)  
  268.  
  269.         {  
  270.  
  271.             Console.WriteLine(this.GetType() + ":" + "ExecuteSuccess");  
  272.  
  273.         }  
  274.  
  275.    
  276.  
  277.         #endregion  
  278.  
  279.    
  280.  
  281.         #region IMethodInject Members  
  282.  
  283.    
  284.  
  285.    
  286.  
  287.         public bool Match(System.Reflection.MethodBase method)  
  288.  
  289.         {  
  290.  
  291.             return true;  
  292.  
  293.         }  
  294.  
  295.    
  296.  
  297.         #endregion  
  298.  
  299.     }  
  300.  
  301.    
  302.  
  303.     [AttributeUsage(AttributeTargets.Method)]  
  304.  
  305.     public class TestAOP1Attribute : Attribute, Green.AOP.IMethodInject  
  306.  
  307.     {  
  308.  
  309.         public int Order 
  310.  
  311.         {  
  312.  
  313.             get;  
  314.  
  315.             set;  
  316.  
  317.         }  
  318.  
  319.    
  320.  
  321.         public int TestProperty  
  322.  
  323.         {  
  324.  
  325.             get;  
  326.  
  327.             set;  
  328.  
  329.         }  
  330.  
  331.    
  332.  
  333.         public string Template  
  334.  
  335.         {  
  336.  
  337.             get;  
  338.  
  339.             set;  
  340.  
  341.         }  
  342.  
  343.    
  344.  
  345.         #region IMethodInject Members  
  346.  
  347.    
  348.  
  349.         public bool Executeing(Green.AOP.MethodExecutionEventArgs args)  
  350.  
  351.         {  
  352.  
  353.             Console.WriteLine(this.GetType() + ":" + "Executeing");  
  354.  
  355.             return true;  
  356.  
  357.         }  
  358.  
  359.    
  360.  
  361.         public Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)  
  362.  
  363.         {  
  364.  
  365.             Console.WriteLine(this.GetType() + ":" + "Exceptioned");  
  366.  
  367.             return Green.AOP.ExceptionStrategy.Handle;  
  368.  
  369.         }  
  370.  
  371.    
  372.  
  373.         public void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)  
  374.  
  375.         {  
  376.  
  377.             Console.WriteLine(this.GetType() + ":" + "ExecuteSuccess");  
  378.  
  379.         }  
  380.  
  381.    
  382.  
  383.         #endregion  
  384.  
  385.    
  386.  
  387.         #region IMethodInject Members  
  388.  
  389.    
  390.  
  391.    
  392.  
  393.         public bool Match(System.Reflection.MethodBase method)  
  394.  
  395.         {  
  396.  
  397.             return true;  
  398.  
  399.         }  
  400.  
  401.    
  402.  
  403.         #endregion  
  404.  
  405.     }  
  406.  
  407.    
  408.  
  409. }  
  410. 复制代码 

注意测试有两种方式(由于没有安装包):

1:先重编译测试项目,运行ConsoleApplication2(在属性中修改控制台其实参数)。在查看测试项目。

2:将项目ConsoleApplication2修改为类库,在添加修改csprojec信息,Task位于Green.AOP.MyBuildTask,具体可以参见上一篇浅谈VS编译自定义编译任务—MSBuild Task(csproject)

在后续将会从简单Demo分析实现原理。

  1. [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]  
  2.     public class PropertyInterceptBase : Attribute, IMethodInject  
  3.     {  
  4.         public PropertyInterceptAction Action 
  5.         {  
  6.             get;  
  7.             set;  
  8.         }  
  9.  
  10.         public int Order 
  11.         {  
  12.             get;  
  13.             set;  
  14.         }  
  15.         #region IMethodInject Members  
  16.  
  17.         public virtual bool Executeing(MethodExecutionEventArgs args)  
  18.         {  
  19.             return true;  
  20.         }  
  21.  
  22.         public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)  
  23.         {  
  24.             return ExceptionStrategy.ReThrow;  
  25.         }  
  26.  
  27.         public virtual void ExecuteSuccess(MethodExecutionEventArgs args)  
  28.         {  
  29.  
  30.         }  
  31.  
  32.         #endregion  
  33.     }  
  34. 复制代码