AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。

在Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。

前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;

早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhen的PostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:

和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。

  • 由于采用 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 Orders
    {
        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;
    }
}

代码很简单,我是采用控制台应用实现的,如果您有兴趣,请下载Demo源码玩玩。

转载于:https://www.cnblogs.com/Hedonister/archive/2007/09/13/892107.html

使用PostSharp进行AOP框架设计:一个简单的原型相关推荐

  1. 初学者-如何使用bootstrap框架设计一个简单的网页主界面HTML+CSS+Bootstrap

    自己也刚刚开始接触框架,在学习了bootstrap框架过后,练习写了一个简单的主界面,主界面的图如下: 这个页面主要用的bootstrap的栅格系统进行整体布局,网页效果简约大方,最重要的是比较简单吧 ...

  2. aop框架的一个简单实现

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 如果传入的是java.util.ArrayList,则返回java.util.ArrayList:如果是ProxyF ...

  3. 如何设计一个简单的KV数据库

    下面的内容仅供设计一个简单的KV数据库.如果想要实现一个功能更强的KV数据库的话,还需要考虑:更加丰富的数据类型.数据压缩.过期机制.数据淘汰策略.集群化.高可用等功能,另外还可以增加统计模块.通知模 ...

  4. 如何利用laragon框架制作一个简单的应用?

    如何利用laragon框架制作一个简单的应用? 一.搭建环境 1. 安装Laragon 1.1 打开安装包用的语言 选择自己习惯用的语言 1.2 选择安装地址 1.3 选择Next,开始install ...

  5. 如何用Java设计一个简单的窗口界面(学习中.1)

    如何用Java设计一个简单的窗口界面 一.前言 二.简单了解 1.Swing简介 2.框架(frame) 3.层次 三.步骤 1.打开eclipse,依次创建项目,包,类. 2.代码 2.1最简单的可 ...

  6. JAVA同时输入用户名和密码_用java模拟设计一个简单的“用户注册”程序。当用户输入用户名和密码时,单击“注...

    用java模拟设计一个简单的"用户注册"程序.当用户输入用户名和密码时,单击"注 2020 - 9 - 26 TAG : 所有功能均已实现,如有不满意的地方我再修改imp ...

  7. python界面设计-手把手教你用Python设计一个简单的命令行界面

    原标题:手把手教你用Python设计一个简单的命令行界面 对 Python 程序来说,完备的命令行界面可以提升团队的工作效率,减少调用时可能碰到的困扰.今天,我们就来教大家如何设计功能完整的 Pyth ...

  8. 设计一个简单分页存储管理系统_【系统架构】如何设计一个简单灵活的收银系统?看这里!(1)...

    在电商项目中,收银系统是一个不可或缺的功能,因为你不仅要通过它来进行收款.退款,而且也要通过它进行财务的对账.报税等.因此,如何设计一个简单灵活的收银系统,对于开发电商项目来说非常重要. 那如何设计一 ...

  9. java完成一个学生信息调查程序_利用Java设计一个简单的学生信息管理程序

    利用Java设计一个简单的控制台学生信息管理程序 此程序可作为课设的参考,其中信息存储于文件中. 创建了学生类Student,用于存储学号等的信息.创建StudentFunction类,用于实现诸如学 ...

最新文章

  1. PHP基础知识(三)
  2. 在项目里交叉使用Swift和OC
  3. cakephp oracle,Cakephp的魔法函数解析,findBy…
  4. 2012.2.18-silverlight设计器崩溃
  5. 【2015年第4期】大数据时代的数据挖掘 —— 从应用的角度看大数据挖掘(下)...
  6. Linux内核原理与分析-第二周作业
  7. Firefox推荐安装插件
  8. spark 类别特征_spark 机器学习基础 数据类型
  9. 库克:苹果正在开发“会震爆你”的未来产品
  10. Java项目集成海康威视门禁,NVR
  11. 应用工具推荐phpStudy(小皮面板)
  12. 房地产类软件实战教程,如何写好房地产类软文
  13. 验证sqlserver 2000 sp4补丁是否安装成功(安装补丁后可以远程访问)
  14. mysql最大整数类型_MySQL教程19-整数类型
  15. 2021强网杯 Web赌徒 WP
  16. getchar()函数的作用
  17. 报警器语音ic单片机芯片如何选型
  18. 解析机智云MCU源码
  19. java 有五个学生_《Java程序设计》 创建5个学生对象,给一个学生数组赋值,每个学生属性有:学号,姓名,年龄。...
  20. 计算机在职博士要考吗,在职博士容易考吗?

热门文章

  1. 一般项目的并发量有多少_汽车保养一般包含哪些项目、保养周期是多少
  2. sumif三个条件怎么填_Excel根据条件进行求和的几个常用函数公式!
  3. 2019下半年系统集成项目管理工程师下午真题
  4. 第二章密码学基础与应用备考要点及真题分布
  5. Java中的方法(形参及实参)return返回类型
  6. Confluence 6 管理协同编辑 - 最大编辑者的限制
  7. arcgis10.1连接sqlserver数据库常见问题(转载)
  8. AFN的简单二次封装
  9. 一步步学习微软InfoPath2010和SP2010--第十一章节--创建批准流程(8)--提交表单操作...
  10. 【转载】利用压缩网页来提升网站浏览速度