.net中使用postsharp来实现aop

本文介绍了PostSharp,一种在.NET中实现面向切面编程(AOP)的工具,详细阐述了静态拦截与动态拦截的区别,AOP的核心思想,以及PostSharp的配置和实现方法。内容包括PostSharp的切面类型如OnMethodBoundaryAspect和OnFieldAccessAspect,切入类型和实例的定义,以及多播和生命周期等,并讨论了PostSharp的优缺点。

postsharp简介

PostSharp是一个用于在.NET平台上实现AOP的框架,相比于uniyt和spring.net框架,postsharp提供了完整的aop架构,比如,可以拦截属性,同时,postsharp使用的是静态拦截,而不是unity和spring.net的动态拦截,关于静态拦截和动态拦截下面会说,而且postsharp是较轻量的,最新稳定版本的postsharp是3.1.45,可以到下面地址去下载, http://www.postsharp.net/download,以vs插件的方式和vs,nuget无缝集成,不过,现在的postsharp分为3个版本,express,pro,ultimate版本,精简版是免费的,专业和旗舰就不免费了,看看价格,对个体程序员来说还是挺贵的,第一年购买$499(Pro版)或$799(Ultimate版),后续的支持费用大约为每年140和250,要上千大洋嘎,每当这个时候,感觉自己都可穷可穷可穷滴,~~~~~~~~~~~~~~~~~~

静态拦截和动态拦截区别

静态拦截AOP的实现思想是给语言的编译器做扩展,使得在编译程序的时候编译器将相应的Aspect代码织入到业务代码的指定连接点,输出整合的结果如下图(以.net为例,postsharp既是静态拦截)

当使用静态拦截时,带AOP扩展的编译器会在编译时将Aspect代码织入业务函数代码,形成整合后的IL,然后交由CLR运行
动态拦截如下图(unity和spring.net都是)



运行时AOP的实现方式是将扩展添加到运行虚拟机而不是编译器,Aspect和业务代码分别独立编译,而在运行时由虚拟机在必要时进行织入

AOP核心思想

在编写代码时将横切关注点分离出来,形成单独的模块,单独编写和维护,不再分散到各业务函数,使得业务函数仅包含核心业务代码,从而解决以上问题。而在程序编译或运行时,通过某些手段(下文介绍)令独立的横切关注点代码可以与核心业务代码自动协作运行,完成本身需要的功能

AOP和语言关系

一般来说,在纯编译型语言(如C、C++)等语言中实现AOP非常困难,必须完全从编译器角度入手,本文讨论托管型语言(如C#,)中AOP的实现方式

环境配置

使用vs2010sp1或者vs2012旗舰版,
下载上面的postsharp扩展,安装即可, key

postsharp实现aop

1.postsharp中Aspect(切面)类型

1) OnMethodBoundaryAspect

postsharp中一个可序列化的抽象类,System.Attribute的子类,可以override  OnEntry、OnExit、OnSuccess、OnException等方法实施拦截,可以读取入参,修改ref、out类型的入参,决定是否调用被拦截的方法体,以及读取、修改方法的返回值等,也可以进行日志记录等操作,拦截时,PostSharp对原方法注入一个try{}catch(){}语句,在适当的位置注入各个拦截事件的调用代码   

2) OnFieldAccessAspect

对field的读取、设置进行拦截处理,override OnGetValue、OnSetValue方法实施拦截,测试过程中无法读取到FieldInfo属性,不知道是不是只有商业版注册后才可以使用这个功能,对field访问的拦截只能适用于当前程序集,如果其他程序集直接诶访问field无法实现拦截,所以对于public、protected类型的field,PostSharp会将field重命名,然后自动生成一个原field名字的property,这会导致依赖的程序集二进制兼容性被破坏,需要重新编译。这个行为也可以通过选项进行配置,阻止PostSharp这样做

3) OnExceptionAspect

    用于实现异常捕获,可以运用于第三方开发的,没有源代码的程序上

4) OnMethodInvocationAspect

override OnInvocation方法实施拦截,PostSharp不是直接修改注入目标程序集,而是为目标方法生成一个委托,修改当前程序集中的调用,改为调用委托,从而实现拦截(这种方式叫做Call-site weaving,调用方织入,对应的另一种方式叫做Target-site weaving,目标织入),这种方式可以实现对第三方程序集方法实施拦截

5) ImplementMethodAspect

 这个aspect用于extern方法、abstract类的方法进行拦截,不要求目标方法有具体的实现

2.postsharp切入类型和实例

一个postsharp使用的过程分三步

1)给项目添加postsharp

安装完postsharp后,右击项目,可以看到PostSharp选项,给这个项目添加PostSharp即可

2)定义aspect

[Serializable]//注意aspect必须是可序列化,用于assembly指令切入
public class ExceptionAspect : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionEventArgs eventArgs)
    {
        Console.WriteLine("开始执行");
    }
    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        Console.WriteLine("成功完成");
    }
}
[Serializable]  //注意aspect必须是可序列化,用于Attribute方式切入,注意下面是多播
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]  
public class ExceptionAttribute : OnMethodBoundaryAspect  
{  
public override void OnEntry(MethodExecutionArgs eventArgs)  
{  
Console.WriteLine("开始执行");  
}  


public override void OnExit(MethodExecutionArgs eventArgs)  
{  
Console.WriteLine("成功完成");  
}  
}  

3)定义拦截

首先定义一个测试项目PostSharp.Test
class Program  
{  
static void Main(string[] args)  
{  
SayHello();  
Console.Read();  
}  
  
public static void SayHello()  
{  
Console.WriteLine("hello");  
}  
}  
postsharp的切入类型有2种,assembly指令和attribute方式
1>assembly指令切入
a)在项目中添加一个assembly指令(就是项目->properties->AssemblyInfo.cs中添加),告诉PostSharp对哪些目标实施拦截
//这里具体到Program类
[assembly: PostSharp.Test.ExceptionAspect(
    AttributeTargetAssemblies = "PostSharp.Test",
    AttributeTargetTypes = "PostSharp.Test.Program")]
b)修改项目文件,让PostSharp在编译完成后能够注入拦截代码:
首先先通过VS的右键菜单卸载项目,如下图

再者通过VS右键编辑项目文件,添加一个import指令如下图:


其次在<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />后面添加一条import指令如下:
           <Import Project="E:\Program Files\PostSharp 3.1.45\PostSharp.targets" />
最后重新加载项目,编译,PostSharp就会在我们指定的位置上使用我们的ExceptionAspect对Program的方法调用注入拦截代码
2>Attribute方式切入
[Exception]//这里使用的是上面定义的第二个aspect
class Program  
{  
static void Main(string[] args)  
{  
SayHello();  
Console.Read();  
}  
  
public static void SayHello()  
{  
Console.WriteLine("hello");  
}  
}  

如上述使用即可

postsharp中Aspect(切面)的生命周期

aspect在编译期实例化,PostSharp将aspect的实例序列化存到assembly中,在运行时再反序列化回来

postsharp中的multicast(多播)

本来我们写一个custom attribute(继承自上面的aspect),必须在每个需要运用的方法、类型上面使用这个attribute,PostSharp中的multicast允许我们可以指定比较宽的一个范围,或者使用正则表达式以及一些filter等,将这个attribute应用到匹配到的多个目标对象上面去,类似于多播这样的效果。比如类指定了某个atrribute,类成员也指定了这个attribute,则PostSharp会为该类的所有field运用这个attribute,从而运用拦截处理,当然了,这种多播拦截,也可以采用assembly指令方式

postsharp的运行机制

PostSharp使用的是静态织入技术,下面我们分析一下PostSharp是如何实现的
首先,当安装PostSharp时,它自动为Visual Studio编译器添加了AOP扩展   
其次当我们编译上述项目时,输出窗口变会多出一些编译信息,类似下面的方式

编译完成 -- 0 个错误,0个警告
postsharp 3.1.45 ************************
=======全部重新生成:生成1个,失败0个,跳过0个=======

很明显,在.NET Complier编译完成后,下面PostSharp又做了一部分工作,这部分工作就是静态织入的过程
我们可以使用反编译工具Reflector或者ILSpy来查看源码,看看postsharp织入了哪些东西,
项目每次编译完成后,PostSharp都会重新织入一次,所以整个过程对程序员是透明的,我们只需维护纯净的业务代码和Aspect代码即可,剩下的工作都由postsharp来完成

postsharp的优缺点

总体来说,使用PostSharp,将会带来如下优点:
横切关注点单独分离出来,提高了代码的清晰性和可维护性。
只要在Aspect中编写辅助性功能代码,在一定程度上减少了工作量和冗余代码。
当然,使用PostSharp也不是没有缺点,主要缺点有如下两方面:
增加了调试的难度。
相比于不用AOP的代码,运行效率有所降低。
所以,对于是否引入AOP,请根据项目具体情况,权衡而定

几点说明

当对同一个方法使用多个该类型的aspect时,可以通过设置或者实现AspectPriority来确定各个拦截器的执行顺序
在aspect之间或者拦截的各个方法之间,可以通过MethodExecutionEventArgs的MethodExecutionTag属性来传递必要的状态信息

总结

postsharp的功能是十分强大的,这里没有说如何拦截字段和属性,也没有说postsharp的cache和dbinvoke功能,只是作为postsharp的简单使用说明来定位的,希望对你有所帮助,看完了postsharp,有没有感觉实现aop是如此的简单那,也难怪人家收费啦,
更多的使用请参考这里  http://www.postsharp.net/aspects#examples

参考地址:

http://www.infoq.com/cn/news/2013/05/PostSharp-3
http://www.cnblogs.com/leoo2sk/archive/2010/11/30/aop-postsharp.html
http://blog.youkuaiyun.com/chenbin520/article/details/9216333
http://www.cnblogs.com/RicCC/archive/2010/04/01/postsharp-demo.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值