使用PostSharp实现AOP编程

 一、AOP(Aspect Oriented Programming):面向切面编程,将业务中的公共部分提取出来统一实现,而不必到处重复编写,体现了DRY原则。

用武之地:性能分析、日志打印、异常捕获、事务处理等。

 

二、由于工作需要,希望对程序中的核心方法做日志跟踪:方法开始执行时,方法参数值是什么,执行时间等

方案一:在这些方法的开始和结束部分编写记录日志

 

 该方案存在代码重复性问题:即要在每个方法内编写重复代码,能否将这种重复的方法提取出来,减少对方法的侵入?答案是AOP。

 

方案二:运用AOP思想,本文选择使用PostSharp实现

 

三、PostSharp 2.0及以上版本分为社区版和商业版,社区版只有少部分功能是可以免费使用的,但已经满足基本需求,故采用PostSharp社区版

PostSharp官网看到社区版和商业版的区别,可以发现哪些特性是能免费使用,请根据实际情况判断是否符合自己项目的需要!

 

 

本文使用开发工具及环境为VS2019,.net framework 4.0,PostSharp-6.8.7.exe

 

1、首先下载并安装PostSharp(从PostSharp官网下载社区版

2、使用Nuget,安装PostSharp包依赖

3、创建日志跟踪特性:LogTraceAttribute

该特性类继承在PostSharp特性类:OnMethodBoundaryAspect

4、重写下面两个方法:

(1)OnEntry方法:进入方法后执行

public override void OnEntry(MethodExecutionArgs args)
{}

 

(2)OnExit方法:方法执行完执行

public override void OnExit(MethodExecutionArgs args)
{}

 

LogTraceAttribute类完整代码如下:

    [Serializable]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    class LogTraceAttribute : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            var parameters = args.Method.GetParameters();

            var printInfo = $"方法:{args.Method.Name},开始执行,时间:{DateTime.Now}";

            Trace.TraceInformation(printInfo);
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            var printInfo = $"方法:{args.Method.Name},结束执行,时间:{DateTime.Now}";

            Trace.TraceInformation(printInfo);
        }
    }

 

5、假设有一个通信类:Communication,该类有如下方法:

(1)Send():用于发送数据

(2)Receive():用于接收数据

现在希望这两个方法开始执行和执行结束后能记录执行时间,则这两个方法应用LogTrace特性即可,Communication完整代码如下:

    class Communication
    {
        [LogTrace]
        public void Send()
        {
            Trace.TraceInformation("发送数据……");
        }

        [LogTrace]
        public void Receive()
        {
            Trace.TraceInformation("接收数据……");
        }
    }

 

6、Main方法中编写如下代码:

        static void Main(string[] args)
        {
            var communication = new Communication();
            communication.Send();

            System.Threading.Thread.Sleep(2000);

            communication.Receive();

            Console.ReadKey();
        }

 

7、执行程序,在输出窗口显示如下输出信息:

PostSharpSample.exe Information: 0 : 方法:Send,开始执行,时间:2021/1/24 22:30:47
PostSharpSample.exe Information: 0 : 发送数据……
PostSharpSample.exe Information: 0 : 方法:Send,结束执行,时间:2021/1/24 22:30:48
PostSharpSample.exe Information: 0 : 方法:Receive,开始执行,时间:2021/1/24 22:30:50
PostSharpSample.exe Information: 0 : 接收数据……
PostSharpSample.exe Information: 0 : 方法:Receive,结束执行,时间:2021/1/24 22:30:50

通过输出信息,可以看到LogTrace特性的OnEntry、OnExit方法将Send方法包裹起来。Receive方法也是如此。

 

8、使用反编译工具dnSpy查看Communication类:

    internal class Communication
    {
        // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
        public void Send()
        {
            MethodExecutionArgs methodExecutionArgs = new MethodExecutionArgs(null, null);
            MethodExecutionArgs methodExecutionArgs2 = methodExecutionArgs;
            MethodBase <<EMPTY_NAME>> = <>z__a_1._3;
            methodExecutionArgs2.Method = <<EMPTY_NAME>>;
            <>z__a_1.a0.OnEntry(methodExecutionArgs);
            try
            {
                Trace.TraceInformation("发送数据……");
            }
            finally
            {
                <>z__a_1.a0.OnExit(methodExecutionArgs);
            }
        }

        // Token: 0x06000002 RID: 2 RVA: 0x000020AC File Offset: 0x000002AC
        public void Receive()
        {
            MethodExecutionArgs methodExecutionArgs = new MethodExecutionArgs(null, null);
            MethodExecutionArgs methodExecutionArgs2 = methodExecutionArgs;
            MethodBase <<EMPTY_NAME>> = <>z__a_1._4;
            methodExecutionArgs2.Method = <<EMPTY_NAME>>;
            <>z__a_1.a1.OnEntry(methodExecutionArgs);
            try
            {
                Trace.TraceInformation("处理接收数据……");
            }
            finally
            {
                <>z__a_1.a1.OnExit(methodExecutionArgs);
            }
        }
    }

红色部分代码是PostSharp注入到程序集中的代码,将方法内容包裹起来,与输出跟踪信息一致。

 

9、总结:PostSharp使用特性实现对方法的非侵入管理,代码看起来简洁优雅。

 

posted @ 2021-01-24 22:56  T-Evan  阅读(828)  评论(0)    收藏  举报