C#当中利用Attribute实现简易AOP

时间:2021-08-04 20:00:49

首先看一段简单的代码:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } //来自UI层的调用 private void button1_Click(object sender, EventArgs e) { BusinessHandler handler = new BusinessHandler(); handler.DoSomething(); } } //业务层的类和方法 public class BusinessHandler { public void DoSomething() { MessageBox.Show("执行了方法本身!"); } }

那么假设这是一个web程序,我们想在按钮点击时,先校验session,然后检验权限、起事务、写日志,然后再执行操作本身,最后再写日志。显然不能把对上面这些操作的方法调用都写在DoSomething()里,这样代码会变成一大坨屎,那我们该怎么办呢?

所谓AOP(面向切面编程)这个唬人的名词就是干这件事用的,其实现方式有很多种,比如利用spring等框架,,但是在实际项目中并不是想引一个框架进来就能随便引的,很多时候都需要我们自己手写一些机制。

这里想到了MVC当中的Filter,只要在Controller或者Action上打一个特性标签(Attribute),就能在方法执行前后做一些其他事情了。那么我们就来简单模拟一个Filter的实现吧。

首先给原先的方法改造一下,改成特性标签这种优雅的方式:

//业务层的类和方法,让它继承自上下文绑定类的基类 [MyInterceptor] public class BusinessHandler : ContextBoundObject { [MyInterceptorMethod] public void DoSomething() { MessageBox.Show("执行了方法本身!"); } }

补充: .NET上下文(ContextBoundObject对象)

什么叫上下文,千万别和ASP.NET中的上下文搞混了,这个上下文是个形容词,在不同的场合有不同的意思。在ASP.NET中的上下文是指Context对象,这个对象基本上包容了HTTP协议的整个生命周期的信息,可以获取到客户端浏览器的一些基本信息,也可以获取到关于HTTP协议的一些信息,等等。

这里所讲的上下文是.NET程序执行的最小逻辑范围,ASP.NET上下文是站在B/S编程模型角度去看待的,而这里的上下文是站在.NET底层运行角度看来的,后者是代码的上下文,前者是整个生命周期的上下文。

在没有接触ContextBoundObject之前我一直以为.NET程序执行的最小逻辑范围是应用程序域(AppDomain),知道了之后才知道另有隐情,上下文是用来确定对象的逻辑归属,在多线程(Thread)、事物处理(Transaction)、企业服务(Enterprise)等方面都需要用上下文来对对象进行规划。

有了特性标签自然就要有特性标签对应的类,以及AOP的实现方法,这些东西可以单独独立到一个文件或程序集里。

首先是贴在方法上的标签,实现为空:

//贴在方法上的标签[MyInterceptorMethod]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class MyInterceptorMethodAttribute : Attribute
{ }

之后定义贴在类上的标签:

//贴在类上的标签 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public sealed class MyInterceptorAttribute : ContextAttribute, IContributeObjectSink { public MyInterceptorAttribute() : base("MyInterceptor") { } //实现IContributeObjectSink接口当中的消息接收器接口 public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next) { return new MyAopHandler(next); } }

补充: 这里继承了ContextAttribute, 在.net中怎么使用attribute,参考: 

这里定义了一个MyAopHandler类,实现如下:

//AOP方法处理类,实现了IMessageSink接口,以便返回给IContributeObjectSink接口的GetObjectSink方法 public sealed class MyAopHandler : IMessageSink { //下一个接收器 private IMessageSink nextSink; public IMessageSink NextSink { get { return nextSink; } } public MyAopHandler(IMessageSink nextSink) { this.nextSink = nextSink; } //同步处理方法 public IMessage SyncProcessMessage(IMessage msg) { IMessage retMsg = null; //方法调用消息接口 IMethodCallMessage call = msg as IMethodCallMessage; //如果被调用的方法没打MyInterceptorMethodAttribute标签 if (call == null || (Attribute.GetCustomAttribute(call.MethodBase, typeof(MyInterceptorMethodAttribute))) == null) { retMsg = nextSink.SyncProcessMessage(msg); } //如果打了MyInterceptorMethodAttribute标签 else { MessageBox.Show("执行之前"); retMsg = nextSink.SyncProcessMessage(msg); MessageBox.Show("执行之后"); } return retMsg; } //异步处理方法(不需要) public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { return null; } }