PostSharp是一种Aspect Oriented Programming 面向切面(或面向方面)的组件框架,适用在.NET开发中,本篇主要介绍Postsharp在.NET开发中的相关知识,以及一些如日志、缓存、事务处理、异常处理等常用的切面处理操作。

AOP(Aspect-Oriented Programming)是一种将函数的辅助性功能与业务逻辑相分离的编程泛型(programming paradigm),其目的是将横切关注点(cross-cutting concerns)分离出来,使得程序具有更高的模块化特性。AOP是面向方面软件开发(Aspect-Oriented Software Development)在编码实现层面上的具体表现。

我们知道,解耦是程序员编码开发过程中一直追求的,AOP也是为了解耦所诞生。引入AOP技术,能很大程度上简化我们编码,减少复制的代码量,也便于统一维护统一的部分代码,如日志、缓存、事务处理、异常处理等常用的处理。

1、AOP框架的介绍

1)AOP技术介绍

AOP技术利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如Avanade公司的高级方案构架师Adam Magee所说,AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

2)AOP使用场景

AOP用来封装横切关注点,具体可以在下面的场景中使用:

Authentication 权限

Caching 缓存

Context passing 内容传递

Error handling 错误处理

Lazy loading 懒加载

Debugging  调试

logging, tracing, profiling and monitoring 记录跟踪 优化 校准

Performance optimization 性能优化

Persistence  持久化

Resource pooling 资源池

Synchronization 同步

Transactions 事务

3)PostSharp框架

PostSharp是一个用于在.NET平台上实现AOP的框架,是比较常用的一个AOP框架,官方网站为http://www.sharpcrafters.com。目前最新版本为4.X,但是是收费的AOP软件。

PostSharp使用静态织入方式实现AOP,其连接点非常丰富,使用简单,而且相对其它一些.NET平台上的AOP框架来说,PostSharp较为轻量级,但是功能却一点也不逊色。

总体来说,使用PostSharp,将会带来如下优点:

  • 横切关注点单独分离出来,提高了代码的清晰性和可维护性。
  • 只要在Aspect中编写辅助性功能代码,在一定程度上减少了工作量和冗余代码。

当然,使用PostSharp也会存在一些缺点,主要缺点有如下两方面:

  • 增加了调试的难度。
  • 相比于不用AOP的代码,运行效率有所降低。

不过瑕不掩瑜,相对于这些缺点问题,使用PostSharp可以极大提高开发效率,减少重复代码,从而提高代码的可读性、可维护性。

另外在GitHub上还有一些开源的AOP组件,例如排头位的是KingAOP(https://github.com/AntyaDev/KingAOP),不过由于它采用了Dynamic的方式来实现,如它的构造对象如下所示。

dynamic helloWorld = new HelloWorld();
helloWorld.HelloWorldCall();

因此虽然比较方便,而且号称和PostSharp使用习惯类似,但是改变了对象的创建方式,对一般项目的类对象处理并不太适合。因此我还是比较倾向于使用PostSharp来进行AOP的编程开发。

2、PostSharp框架的使用

1)准备PostSharp的编译环境

PostSharp目前版本是4.x,我在官网下载了进行使用,不过经常发生"Error connecting to the pipe server. See previous warnings for details.",后来干脆使用了3.x版本的,反而能够正常使用,非常不错,呵呵。

PostSharp是一个可以安装在VS上的插件,安装后在VS的菜单栏目里面增加了一个PostSharp的菜单项,如下所示。

一般项目如果需要使用PostSharp特性的,在项目属性的【PostSharp】选项页中,使用【Add PostSharp to this project】把PostSharp加入到项目里面进行使用。

添加后,会弹出PostSharp的插件提示对话框,提示将加入相应的PostSharp包等内容,如下所示。

完成后就可以在项目中使用PostSharp的相关类了。

2)增加PostSharp的AOP切面处理

一般约定每个Aspect类的命名必须为“XXXAttribute”的形式。其中“XXX”就是这个Aspect的名字。PostSharp中提供了丰富的内置“Base Aspect”以便我们继承,其中这里我们继承“OnMethodBoundaryAspect ”,这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关。

日志的Aspect类的代码如下所示。

    [Serializable]
public class LogAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
Console.WriteLine(Environment.NewLine); Console.WriteLine("Entering [ {0} ] ...", args.Method); base.OnEntry(args);
} public override void OnExit(MethodExecutionArgs args)
{
Console.WriteLine("Leaving [ {0} ] ...", args.Method); base.OnExit(args);
}
}

异常处理的类代码如下所示。

    [Serializable]
public class ExceptionAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
Console.WriteLine(String.Format("Exception in :[{0}] , Message:[{1}]", args.Method, args.Exception.Message));
args.FlowBehavior = FlowBehavior.Continue; base.OnException(args);
}
}

计时处理的Aspect类代码如下所示。

    [Serializable]
[MulticastAttributeUsage(MulticastTargets.Method)]
public class TimingAttribute : PostSharp.Aspects.OnMethodBoundaryAspect
{
[NonSerialized]
Stopwatch _StopWatch; public override void OnEntry(PostSharp.Aspects.MethodExecutionArgs args)
{
_StopWatch = Stopwatch.StartNew(); base.OnEntry(args);
} public override void OnExit(PostSharp.Aspects.MethodExecutionArgs args)
{
Console.WriteLine(string.Format("[{0}] took {1}ms to execute",
new StackTrace().GetFrame().GetMethod().Name,
_StopWatch.ElapsedMilliseconds)); base.OnExit(args);
}
}

事务处理的Aspect类代码如下所示。

    [Serializable]
[AspectTypeDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, typeof(LogAttribute))]
public class RunInTransactionAttribute : OnMethodBoundaryAspect
{
[NonSerialized]
TransactionScope TransactionScope; public override void OnEntry(MethodExecutionArgs args)
{
this.TransactionScope = new TransactionScope(TransactionScopeOption.RequiresNew);
} public override void OnSuccess(MethodExecutionArgs args)
{
this.TransactionScope.Complete();
} public override void OnException(MethodExecutionArgs args)
{
args.FlowBehavior = FlowBehavior.Continue;
Transaction.Current.Rollback();
Console.WriteLine("Transaction Was Unsuccessful!");
} public override void OnExit(MethodExecutionArgs args)
{
this.TransactionScope.Dispose();
}
}

下面是几个Aspect类的切面处理代码,如下所示。

        [Exception]
[Log]
static void Calc()
{
throw new DivideByZeroException("A Math Error Occured...");
} [Log, Timing]
static void LongRunningCalc()
{
//wait for 1000 miliseconds
Thread.Sleep();
}

从上面我们可以看到,常规的异常处理、日志处理都已经通过Attribute的方式进行处理了,在函数体里面都只是剩下具体的业务逻辑代码了,这样极大提高了代码的可读性,简洁明了。

运行上面的代码函数的调用,我们可以在输出日志里面看到具体的结果内容。

Entering [ Void Calc() ] ...
“System.DivideByZeroException”类型的第一次机会异常在 PostSharpExample.exe 中发生
Exception in :[Void Calc()] , Message:[A Math Error Occured...]
Leaving [ Void Calc() ] ... Entering [ Void LongRunningCalc() ] ...
Leaving [ Void LongRunningCalc() ] ...
[LongRunningCalc] took 1002ms to execute

这样,通过声明的方式,就实现了常规日志 、异常的处理,当然实际项目上使用日志、异常处理的这些代码肯定会更加复杂一些,不过小例子已经实现了切面逻辑的分离处理了,尘归尘、土归土,一切都是那么的简洁安静了。

在.NET项目中使用PostSharp,实现AOP面向切面编程处理的更多相关文章

  1. Spring 08: AOP面向切面编程 + 手写AOP框架

    核心解读 AOP:Aspect Oriented Programming,面向切面编程 核心1:将公共的,通用的,重复的代码单独开发,在需要时反织回去 核心2:面向接口编程,即设置接口类型的变量,传入 ...

  2. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  3. 极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介

    仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...

  4. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...

  5. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...

  6. Method Swizzling和AOP(面向切面编程)实践

    Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...

  7. 【原创】Android AOP面向切面编程AspectJ

    一.背景: 在项目开发中,对 App 客户端重构后,发现用于统计用户行为的友盟统计代码和用户行为日志记录代码分散在各业务模块中,比如在视频模块,要想实现对用户对监控点的实时预览和远程回放行为进行统计, ...

  8. 论AOP面向切面编程思想

    原创: eleven 原文:https://mp.weixin.qq.com/s/8klfhCkagOxlF1R0qfZsgg [前言] AOP(Aspect-Oriented Programming ...

  9. Aspects– iOS的AOP面向切面编程的库

    简介 一个简洁高效的用于使iOS支持AOP面向切面编程的库.它可以帮助你在不改变一个类或类实例的代码的前提下,有效更改类的行为.比iOS传统的 AOP方法,更加简单高效.支持在方法执行的前/后或替代原 ...

  10. Spring Boot2(六):使用Spring Boot整合AOP面向切面编程

    一.前言 众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转.本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理. 二.何为aop ​ aop全称Aspec ...

随机推荐

  1. 使用SimpleAdapter创建ListView

    通过ArrayAdapter实现Adapter虽然简单.易用,但ArrayAdapter的功能比较有限.它的每个列表只能是TextView.如果开发者需呀实现更复杂的列表项,则可以考虑使用Simple ...

  2. CaltrainTimes从设计到发布(基于Flex的手机应用)

    资源下载地址 Caltrain Times 的 iTunes下载地址 Caltrain Times的Android Market 下载地址 Caltrain Times的BlackBerry App ...

  3. WebRTC音视频引擎研究(2)--VoiceEngine音频编解码器数据结构以及参数设置

    1.VoiceEngine Codec数据结构 WebRTC中,用一个结构体struct CodecInst表示特定的音频编解码器对象: struct CodecInst { int pltype;  ...

  4. 【G】开源的分布式部署解决方案(二) - 好项目是从烂项目基础上重构出来的

    分析目前项目结构 眼前出现这么一坨坨的文件夹,相信很多人已经看不下去了.是的,首先就是要把它给做掉. 按照这个项目文件夹的命名意图,大概可以划分如下: 1.Business:业务代码 2.Data:数 ...

  5. B树的查找、插入、删除(附源代码)

    B-Tree Index B-Tree搜索 B-Tree插入 分裂节点 插入节点 B-Tree删除 合并节点 删除节点 Basic B-Tree有两个比较重要的性质: 所有的leaf均在同一个leve ...

  6. 关于echarts地图下钻。

     在去年十二月份,前端老大交代个任务,关于地图下钻.这里做了个简单的青岛地图下钻,初学echarts,做的不精,凑合看看吧. 第一步呢,先引入echarts等文件,这是最基本的.  第二步,到官网下载 ...

  7. 多线程方式实现Socket通信

    一.首先,介绍下两类传输协议:TCP:UDP TCP是Tranfer Control Protocol的 简称,是一种面向连接的保证可靠传输的协议.通过TCP协议传输,得到的是一个顺序的无差错的数据流 ...

  8. Express之get,pos请求参数的获取

    Express的版本4.X Get query参数的获取 url假设:http://localhost:3000/users/zqzjs?name=zhaoqize&word=cool& ...

  9. 进程——wait与waitpid、僵尸进程与孤儿进程

    僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB.使其成为僵尸进程 孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程 为了 ...

  10. mybatis入门-第一个程序

    今天,我们就一起来完成mybatis的第一个小demo,使用mybatis对我们的数据库进行一个小小的操作. 需求 根据用户id查询用户的信息. 环境搭建 java环境:jdk1.7版本 开发工具:e ...