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.Testclass 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]//这里使用的是上面定义的第二个aspectclass 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-3http://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