• MSBuild + MSILInect实现编译时AOP之预览


          在本文之前的前几篇浅谈.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
    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
        
    public class MethodInterceptBase : Attribute, IMethodInject
        {
            
    public int Order
            {
                
    get;
                
    set;
            }
            
    #region IMethodInject Members

            
    public virtual bool Executeing(MethodExecutionEventArgs args)
            {
                
    return true;
            }

            
    public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)
            {
                
    return ExceptionStrategy.ReThrow;
            }

            
    public virtual void ExecuteSuccess(MethodExecutionEventArgs args)
            {

            }
           
            
    #endregion
    }

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

    View Code
     
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]

        
    public class MatchedMethodInterceptBase : Attribute, IMethodInject

        {

            
    public int Order

            {

                
    get;

                
    set;

            }

     

            
    public string Rule

            {

                
    get;

                
    set;

            }

            
    #region IMethodInject Members


            
    public virtual bool Executeing(MethodExecutionEventArgs args)

            {

                
    return true;

            }
     

            
    public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)

            {

                
    return ExceptionStrategy.ReThrow;

            }

     

            
    public virtual void ExecuteSuccess(MethodExecutionEventArgs args)

            {

     

            }

           

            
    #endregion

        }

     
    3PropertyInterceptBase实现属性的注入,其属性Actionenum PropertyInterceptActionNone Get, Set)指注入属性的get或者Set 
    View Code
     
    [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
        
    public class PropertyInterceptBase : Attribute, IMethodInject
        {
            
    public PropertyInterceptAction Action
            {
                
    get;
                
    set;
            }

            
    public int Order
            {
                
    get;
                
    set;
            }
            
    #region IMethodInject Members

            
    public virtual bool Executeing(MethodExecutionEventArgs args)
            {
                
    return true;
            }

            
    public virtual ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)
            {
                
    return ExceptionStrategy.ReThrow;
            }

            
    public virtual void ExecuteSuccess(MethodExecutionEventArgs args)
            {

            }

            
    #endregion
        }

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

    下面是一个简单测试Code:

    View Code
    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Reflection;

    using Green.AOP;

     

    namespace Test

    {   

        
    // [TestAOP2Attribute(Rule = "TestMethod1*")]

        
    public class Class1

        {

            
    // [TestAOPPropertyAttribute(Action = PropertyInterceptAction.Set)]

            [TestAOPPropertyGetAttribute(Action 
    = PropertyInterceptAction.Get)]

            
    public testStrust TestProperty

            {

                
    get;

                
    set;

            }

            [Obsolete()]

            
    public static void Main(string[] args)

            {          

                
    try

                {

                    var y 
    = new Class1();

                    
    // y.TestProperty = DateTime.Now;

                    Console.WriteLine(y.TestProperty);

                }

                
    catch (Exception ex)

                {

                    Console.WriteLine(ex.ToString());

                }

                
    // new Class1().TestMethod1(1, 2, null);

                Console.Read();

                
    //throw new Exception("exfffffffffffffffffffff");

            }

            
    //[TestAOPAttribute(Order=1)]

            
    //[TestAOP1Attribute(TestProperty = 1, Template = "sdsdsd",Order=0)]

            
    public Class1 TestMethod1(int i, int j, Class1 c)

            {

                Console.WriteLine(
    "ok");

                
    return new Class1();

            }

        }

        
    public class TestAOPPropertyGetAttribute : Green.AOP.PropertyInterceptBase

        {

            
    #region IMethodInject Members

            
    public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    "------------------" + args);

                Console.WriteLine(args.Instance);

                Console.WriteLine(args.Method);

                Console.WriteLine(
    this.GetType() + ":" + "Executeing");

                
    return true;

            }

            
    public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Exceptioned");

                
    return Green.AOP.ExceptionStrategy.ReThrow;

            }

            
    public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    "-----------");

                Console.WriteLine(
    this.GetType() + ":" + "ExecuteSuccess" + "--result:" + args.ReturnValue);

            }

            
    #endregion

        }

        
    public class TestAOPPropertyAttribute : Green.AOP.PropertyInterceptBase

        {

            
    #region IMethodInject Members

            
    public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(args.Instance);

                Console.WriteLine(args.Method);

                Console.WriteLine(
    this.GetType() + ":" + "Executeing");

                
    return true;

            }

            
    public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Exceptioned");

                
    return Green.AOP.ExceptionStrategy.Handle;

            }

            
    public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

           {

                Console.WriteLine(
    this.GetType() + ":" + "ExecuteSuccess");

            }

            
    #endregion

        }

        
    public class TestAOP2Attribute : Green.AOP.MatchedMethodInterceptBase

        {

            
    #region IMethodInject Members

            
    public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(args.Instance);

                Console.WriteLine(args.Method);

                Console.WriteLine(
    this.GetType() + ":" + "Executeing");

                
    return true;

            }

            
    public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Exceptioned");

                
    return Green.AOP.ExceptionStrategy.Handle;

            }

            
    public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "ExecuteSuccess");

            }

            
    #endregion

            
    #region IMethodInject Members

            
    public bool Match(System.Reflection.MethodBase method)

            {

                
    return true;

            }

            
    #endregion

        }

     

        
    //[AttributeUsage(AttributeTargets.Method)]

        
    public class TestAOPAttribute : Green.AOP.MethodInterceptBase

        {

            
    #region IMethodInject Members

            
    public override bool Executeing(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Executeing");

                
    return true;

            }

     

            
    public override Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Exceptioned");

                
    return Green.AOP.ExceptionStrategy.Handle;

            }

     

            
    public override void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "ExecuteSuccess");

            }

     

            
    #endregion

     

            
    #region IMethodInject Members

     

     

            
    public bool Match(System.Reflection.MethodBase method)

            {

                
    return true;

            }

     

            
    #endregion

        }

     

        [AttributeUsage(AttributeTargets.Method)]

        
    public class TestAOP1Attribute : Attribute, Green.AOP.IMethodInject

        {

            
    public int Order

            {

                
    get;

                
    set;

            }

     

            
    public int TestProperty

            {

                
    get;

                
    set;

            }

     

            
    public string Template

            {

                
    get;

                
    set;

            }

     

            
    #region IMethodInject Members

     

            
    public bool Executeing(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Executeing");

                
    return true;

            }

     

            
    public Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "Exceptioned");

                
    return Green.AOP.ExceptionStrategy.Handle;

            }

     

            
    public void ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

            {

                Console.WriteLine(
    this.GetType() + ":" + "ExecuteSuccess");

            }

     

            
    #endregion

     

            
    #region IMethodInject Members

     

     

            
    public bool Match(System.Reflection.MethodBase method)

            {

                
    return true;

            }

     

            
    #endregion

        }

     

    }

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

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

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

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

     


    作者:破  狼
    出处:http://www.cnblogs.com/whitewolf/
    本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。该文章也同时发布在我的独立博客中-个人独立博客博客园--破狼51CTO--破狼

  • 相关阅读:
    Web_0012:FTP文件编辑器关联
    JS_0033:判断苹果安卓 微信浏览器,并在苹果微信浏览器下做特别处理
    JS_0032:匿名函数 function前加 ! 或 function用括号包裹起来 含义
    JS_0031:JS 常用方法
    spark为什么用scala语言开发
    spark开发常见问题
    java实现多继承
    数仓架构
    object类中的方法
    Spring的IOC原理
  • 原文地址:https://www.cnblogs.com/whitewolf/p/2132217.html
Copyright © 2020-2023  润新知