前段时间做一个权限系统,在考虑日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现;这两天又重新学习研究了PostSharp的架构与实现思想,将其融入现有框架; 

由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。 还可以拦截 Field Access、Exception 等操作。 无需将对象创建代码改成 "new proxy()",更加透明。 可以使用通配符进行多重拦截匹配。 静态注入带来的问题更多的是注入代码的质量和调试复杂度。 另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。 
我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常; 
按以前的写法我们可能很麻烦,我们要如此这般的写: 

 

 

public class XOrders
    {
        public bool Add(string id, string orderName)
        {
            try
            {
                if (User.AddEnable)
                {
                    //TODO:新增订单的实现
                    Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
                    Console.ReadLine();
                    Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
                    return true;
                }
                else
                {
                    //
                }
            }
            catch (Exception)
            {
                //TODO:记录异常的实现
                throw;
            } 

            return true; 

        } 

        public bool Delete(string id)
        {
            try
            {
                if (User.DeleteEnable)
                {
                    //TODO:删除订单的实现
                    Console.WriteLine("您删除订单成功:编号:{0}", id);
                }
                else
                {
                    //
                } 

            }
            catch (Exception)
            {
                //TODO:记录异常的实现
                throw;
            } 

            return true;
        } 

 

 

这种写的弊端我就不多说了,有很多先驱都阐述过…… 
我要演示的是采用AOP技术的框架原型实现: 
首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码) 
然后我们实现Orders对象 

 

 

using System; 

namespace PostSharp.Demo
{
    public class Orders
    {
        [Permission]
        [Exception]
        public bool Add(string id, string orderName)
        {
            Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
            Console.ReadLine();
            Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
            return true;
        } 

        [Logger]
        [Permission]
        [Exception]
        public bool Delete(string id)
        {
            Console.WriteLine("您删除订单成功:编号:{0}", id); 

            return true;
        }
    }
} 

 

 

当然还要模拟一个用户资格认证 

 

 

namespace PostSharp.Demo
{
    /// <summary>
    /// 静态的用户对象,用于存放当前登录用户,成员资格
    /// </summary>
    public static class User
    {
        private static string _userId; 

        public static string UserId
        {
            get { return _userId; }
            set { _userId = value; }
        } 

        public static bool AddEnable
        {
            get
            {
                return (_userId.ToLower() == "admin");
            }
        } 

        public static bool DeleteEnable
        {
            get
            {
                return (_userId.ToLower() == "admin");
            }
        }
    }
} 

 

 

再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute…… 
PermissionAttribute 

 

 

using System;
using PostSharp.Laos; 

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
    public class PermissionAttribute : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionEventArgs eventArgs)
        {
            if (!User.AddEnable)
            {
                Console.WriteLine("用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);
                eventArgs.FlowBehavior = FlowBehavior.Return;
            } 

        }
    }
} 

LoggerAttribute 

using System;
using PostSharp.Laos; 

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
    public sealed class LoggerAttribute : OnMethodInvocationAspect
    {
        public override void OnInvocation(MethodInvocationEventArgs eventArgs)
        {
            DateTime time = DateTime.Now;
            string log = "时间:{0},操作人员:{1},操作:{2}!"; 

            object[] arg = eventArgs.GetArguments(); 

            log = String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!"); 

            System.IO.File.WriteAllText("C:\\Log.Txt", log);
        }
    }
} 

ExceptionAttribute 

using System;
using PostSharp.Laos; 

namespace PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
    public class ExceptionAttribute : OnExceptionAspect
    {
        public override void OnException(MethodExecutionEventArgs eventArgs)
        {
            Console.WriteLine("程序出现异常:{0}", eventArgs.Exception.Message);
            eventArgs.FlowBehavior = FlowBehavior.Return;
        }
    }
} 

 

然后再用控制台程序测试下能不能成功 

 

 

Orders order = new Orders();
            Console.WriteLine("请输入用户名:");
            User.UserId = Console.ReadLine();
            Console.WriteLine("请输入密码:");
            Console.ReadLine();
            string id; 

            LRedo:
            Console.WriteLine("请输入您要执行的操作:新增(A),删除(D),退出(X)"); 

            string opt = Console.ReadLine(); 

            if (opt.ToLower() == "a")
            {
                Console.WriteLine("请输入订单编号:");
                id = Console.ReadLine(); 

                Console.WriteLine("请输入订单名称:");
                string name = Console.ReadLine();
                order.Add(id, name);
            }
            else if (opt.ToLower() == "d")
            {
                Console.WriteLine("请输入订单编号:");
                id = Console.ReadLine();
                order.Delete(id);
            }
            else if (opt.ToLower() == "x")
            {
            }
            else
            {
                Console.WriteLine("您的输入不正确,请重新输入!");
                goto LRedo;
            } 

            Console.WriteLine("按任意键退出……");
            Console.ReadLine(); 

 

写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了

 

public class Orders
{
    // Methods
    static Orders()
    {
        if (!~PostSharp~Laos~Implementation.initialized)
        {
            LaosNotInitializedException.Throw();
        }
        ~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);
        ~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
        ~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);
        ~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);
        ~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);
        ~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);
        ~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);
        ~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);
        ~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);
        ~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);
    } 

    private bool ~Delete(string id)
    {
        Console.WriteLine("您删除订单成功:编号:{0}", id);
        return true;
    } 

    public bool Add(string id, string orderName)
    {
        bool ~returnValue~1;
        MethodExecutionEventArgs ~laosEventArgs~7;
        try
        {
            object[] ~arguments~6 = new object[] { id, orderName };
            ~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~6);
            ~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);
            if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)
            {
                return (bool) ~laosEventArgs~7.ReturnValue;
            }
            try
            {
                Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
                Console.ReadLine();
                Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
                ~returnValue~1 = true;
            }
            catch (Exception ~exception~2)
            {
                object[] ~arguments~3 = new object[] { id, orderName };
                MethodExecutionEventArgs ~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this, ~arguments~3);
                ~laosEventArgs~4.Exception = ~exception~2;
                ~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);
                switch (~laosEventArgs~4.FlowBehavior)
                {
                    case FlowBehavior.Continue:
                        goto Label_0145; 

                    case FlowBehavior.Return:
                        ~returnValue~1 = (bool) ~laosEventArgs~4.ReturnValue;
                        goto Label_0145;
                }
                throw;
            }
        Label_0145:
            ~laosEventArgs~7.ReturnValue = ~returnValue~1;
            ~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);
            ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;
        }
        catch (Exception ~exception~5)
        {
            ~laosEventArgs~7.Exception = ~exception~5;
            ~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);
            switch (~laosEventArgs~7.FlowBehavior)
            {
                case FlowBehavior.Continue:
                    return ~returnValue~1; 

                case FlowBehavior.Return:
                    return (bool) ~laosEventArgs~7.ReturnValue;
            }
            throw;
        }
        finally
        {
            ~laosEventArgs~7.ReturnValue = ~returnValue~1;
            ~PostSharp~Laos~Implementation.~aspect~1.OnExit(~laosEventArgs~7);
            ~returnValue~1 = (bool) ~laosEventArgs~7.ReturnValue;
        }
        return ~returnValue~1;
    } 

    [DebuggerNonUserCode]
    public bool Delete(string id)
    {
        bool ~returnValue~2;
        MethodExecutionEventArgs ~laosEventArgs~8;
        try
        {
            object[] ~arguments~7 = new object[] { id };
            ~laosEventArgs~8 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~7);
            ~PostSharp~Laos~Implementation.~aspect~2.OnEntry(~laosEventArgs~8);
            if (~laosEventArgs~8.FlowBehavior == FlowBehavior.Return)
            {
                return (bool) ~laosEventArgs~8.ReturnValue;
            }
            try
            {
                Delegate delegateInstance = new ~PostSharp~Laos~Implementation.~delegate~0(this.~Delete);
                object[] arguments = new object[] { id };
                MethodInvocationEventArgs eventArgs = new MethodInvocationEventArgs(delegateInstance, arguments);
                ~PostSharp~Laos~Implementation.~aspect~5.OnInvocation(eventArgs);
                ~returnValue~2 = (bool) eventArgs.ReturnValue;
            }
            catch (Exception ~exception~3)
            {
                object[] ~arguments~4 = new object[] { id };
                MethodExecutionEventArgs ~laosEventArgs~5 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this, ~arguments~4);
                ~laosEventArgs~5.Exception = ~exception~3;
                ~PostSharp~Laos~Implementation.~aspect~4.OnException(~laosEventArgs~5);
                switch (~laosEventArgs~5.FlowBehavior)
                {
                    case FlowBehavior.Continue:
                        goto Label_0160; 

                    case FlowBehavior.Return:
                        ~returnValue~2 = (bool) ~laosEventArgs~5.ReturnValue;
                        goto Label_0160;
                }
                throw;
            }
        Label_0160:
            ~laosEventArgs~8.ReturnValue = ~returnValue~2;
            ~PostSharp~Laos~Implementation.~aspect~2.OnSuccess(~laosEventArgs~8);
            ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;
        }
        catch (Exception ~exception~6)
        {
            ~laosEventArgs~8.Exception = ~exception~6;
            ~PostSharp~Laos~Implementation.~aspect~2.OnException(~laosEventArgs~8);
            switch (~laosEventArgs~8.FlowBehavior)
            {
                case FlowBehavior.Continue:
                    return ~returnValue~2; 

                case FlowBehavior.Return:
                    return (bool) ~laosEventArgs~8.ReturnValue;
            }
            throw;
        }
        finally
        {
            ~laosEventArgs~8.ReturnValue = ~returnValue~2;
            ~PostSharp~Laos~Implementation.~aspect~2.OnExit(~laosEventArgs~8);
            ~returnValue~2 = (bool) ~laosEventArgs~8.ReturnValue;
        }
        return ~returnValue~2;
    }
} 

 

这里可以看出,如果是在AOP的异常捕获里面标记 eventArgs.FlowBehavior = FlowBehavior.Return,那么标记的方法将不会执行。