使用PostSharp进行AOP框架设计:一个简单的原型

AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。

Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。

前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;

早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhenPostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:

和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。

  • 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
  • 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
  • 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
  • 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
  • 还可以拦截 Field Access、Exception 等操作。
  • 无需将对象创建代码改成 "new proxy()",更加透明。
  • 可以使用通配符进行多重拦截匹配。
  • 静态注入带来的问题更多的是注入代码的质量和调试复杂度。

另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。

我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;

按以前的写法我们可能很麻烦,我们要如此这般的写:

public   class  Orders
    {
        
public   bool  Add( string  id,  string  orderName)
        {
            
try
            {
                
if  (User.AddEnable)
                {
                    
// TODO:新增订单的实现
                    Console.WriteLine( " 正在执行新增订单方法的操作,回车继续…… " );
                    Console.ReadLine();
                    Console.WriteLine(
" 您添加订单成功:编号:{0},名称:{1} " , id, orderName);
                    
return   true ;
                }
                
else
                {
                    
//
                }
            }
            
catch  (Exception)
            {
                
// TODO:记录异常的实现
                 throw ;
            }

            
return   true ;

        }

        
public   bool  Delete( string  id)
        {
            
try
            {
                
if  (User.DeleteEnable)
                {
                    
// TODO:删除订单的实现
                    Console.WriteLine( " 您删除订单成功:编号:{0} " , id);
                }
                
else
                {
                    
//
                }

            }
            
catch  (Exception)
            {
                
// TODO:记录异常的实现
                 throw ;
            }

            
return   true ;
        }

这种写的弊端我就不多说了,有很多先驱都阐述过……

我要演示的是采用AOP技术的框架原型实现:

首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)

然后我们实现Orders对象

using  System;

namespace  PostSharp.Demo
{
    
public   class  Orders
    {
        [Permission]
        [Exception]
        
public   bool  Add( string  id,  string  orderName)
        {
            Console.WriteLine(
" 正在执行新增订单方法的操作,回车继续…… " );
            Console.ReadLine();
            Console.WriteLine(
" 您添加订单成功:编号:{0},名称:{1} " , id, orderName);
            
return   true ;
        }

        [Logger]
        [Permission]
        [Exception]
        
public   bool  Delete( string  id)
        {
            Console.WriteLine(
" 您删除订单成功:编号:{0} " , id);

            
return   true ;
        }
    }
}

当然还要模拟一个用户资格认证


namespace  PostSharp.Demo
{
    
///   <summary>
    
///  静态的用户对象,用于存放当前登录用户,成员资格
    
///   </summary>
     public   static   class  User
    {
        
private   static   string  _userId;

        
public   static   string  UserId
        {
            
get  {  return  _userId; }
            
set  { _userId  =  value; }
        }

        
public   static   bool  AddEnable
        {
            
get
            {
                
return  (_userId.ToLower()  ==   " admin " );
            }
        }

        
public   static   bool  DeleteEnable
        {
            
get
            {
                
return  (_userId.ToLower()  ==   " admin " );
            }
        }
    }
}

再然后我们实现 权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……

PermissionAttribute

using  System;
using  PostSharp.Laos;

namespace  PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
=   true , AllowMultiple  =   false )]
    
public   class  PermissionAttribute : OnMethodBoundaryAspect
    {
        
public   override   void  OnEntry(MethodExecutionEventArgs eventArgs)
        {
            
if  ( ! User.AddEnable)
            {
                Console.WriteLine(
" 用户:【{0}】没有权限:【{1}】 " , User.UserId, eventArgs.Method);
                eventArgs.FlowBehavior 
=  FlowBehavior.Return;
            }

        }
    }
}

LoggerAttribute
using  System;
using  PostSharp.Laos;

namespace  PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
=   true , AllowMultiple  =   false )]
    
public   sealed   class  LoggerAttribute : OnMethodInvocationAspect
    {
        
public   override   void  OnInvocation(MethodInvocationEventArgs eventArgs)
        {
            DateTime time 
=  DateTime.Now;
            
string  log  =   " 时间:{0},操作人员:{1},操作:{2}! " ;

            
object [] arg  =  eventArgs.GetArguments();

            log 
=  String.Format(log, time, User.UserId,  " 删除Id为 "   +  arg[ 0 ].ToString()  +   " 的订单! " );

            System.IO.File.WriteAllText(
" C:\\Log.Txt " , log);
        }
    }
}

ExceptionAttribute
using  System;
using  PostSharp.Laos;

namespace  PostSharp.Demo
{
    [Serializable]
    [global::System.AttributeUsage(AttributeTargets.All, Inherited 
=   true , AllowMultiple  =   false )]
    
public   class  ExceptionAttribute : OnExceptionAspect
    {
        
public   override   void  OnException(MethodExecutionEventArgs eventArgs)
        {
            Console.WriteLine(
" 程序出现异常:{0} " , eventArgs.Exception.Message);
            eventArgs.FlowBehavior 
=  FlowBehavior.Return;
        }
    }
}

然后再用控制台程序测试下能不能成功
Orders order  =   new  Orders();
            Console.WriteLine(
" 请输入用户名: " );
            User.UserId 
=  Console.ReadLine();
            Console.WriteLine(
" 请输入密码: " );
            Console.ReadLine();
            
string  id;

            LRedo:
            Console.WriteLine(
" 请输入您要执行的操作:新增(A),删除(D),退出(X) " );

            
string  opt  =  Console.ReadLine();

            
if  (opt.ToLower()  ==   " a " )
            {
                Console.WriteLine(
" 请输入订单编号: " );
                id 
=  Console.ReadLine();

                Console.WriteLine(
" 请输入订单名称: " );
                
string  name  =  Console.ReadLine();
                order.Add(id, name);
            }
            
else   if  (opt.ToLower()  ==   " d " )
            {
                Console.WriteLine(
" 请输入订单编号: " );
                id 
=  Console.ReadLine();
                order.Delete(id);
            }
            
else   if  (opt.ToLower()  ==   " x " )
            {
            }
            
else
            {
                Console.WriteLine(
" 您的输入不正确,请重新输入! " );
                
goto  LRedo;
            }

            Console.WriteLine(
" 按任意键退出…… " );
            Console.ReadLine();

写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?
反编译后的代码
public class Orders
{
    
// Methods
    static Orders()
    {
        
if (!~PostSharp~Laos~Implementation.initialized)
        {
            LaosNotInitializedException.Throw();
        }
        
~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(Orders.Add);
        
~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
        
~PostSharp~Laos~Implementation.~targetMethod~5 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~5.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~5);
        
~PostSharp~Laos~Implementation.~targetMethod~4 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~4.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~4);
        
~PostSharp~Laos~Implementation.~targetMethod~3 = methodof(Orders.Add);
        
~PostSharp~Laos~Implementation.~aspect~3.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~3);
        
~PostSharp~Laos~Implementation.~targetMethod~2 = methodof(Orders.Delete);
        
~PostSharp~Laos~Implementation.~aspect~2.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~2);
    }

    
private bool ~Delete(string id)
    {
        Console.WriteLine(
"您删除订单成功:编号:{0}", id);
        
return true;
    }

    
public bool Add(string id, string orderName)
    {
        
bool ~returnValue~1;
        MethodExecutionEventArgs 
~laosEventArgs~7;
        
try
        {
            
object[] ~arguments~6 = new object[] { id, orderName };
            
~laosEventArgs~7 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this~arguments~6);
            
~PostSharp~Laos~Implementation.~aspect~1.OnEntry(~laosEventArgs~7);
            
if (~laosEventArgs~7.FlowBehavior == FlowBehavior.Return)
            {
                
return (bool~laosEventArgs~7.ReturnValue;
            }
            
try
            {
                Console.WriteLine(
"正在执行新增订单方法的操作,回车继续……");
                Console.ReadLine();
                Console.WriteLine(
"您添加订单成功:编号:{0},名称:{1}", id, orderName);
                
~returnValue~1 = true;
            }
            
catch (Exception ~exception~2)
            {
                
object[] ~arguments~3 = new object[] { id, orderName };
                MethodExecutionEventArgs 
~laosEventArgs~4 = new MethodExecutionEventArgs(methodof(Orders.Add, Orders), this~arguments~3);
                
~laosEventArgs~4.Exception = ~exception~2;
                
~PostSharp~Laos~Implementation.~aspect~3.OnException(~laosEventArgs~4);
                
switch (~laosEventArgs~4.FlowBehavior)
                {
                    
case FlowBehavior.Continue:
                        
goto Label_0145;

                    
case FlowBehavior.Return:
                        
~returnValue~1 = (bool~laosEventArgs~4.ReturnValue;
                        
goto Label_0145;
                }
                
throw;
            }
        Label_0145:
            
~laosEventArgs~7.ReturnValue = ~returnValue~1;
            
~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(~laosEventArgs~7);
            
~returnValue~1 = (bool~laosEventArgs~7.ReturnValue;
        }
        
catch (Exception ~exception~5)
        {
            
~laosEventArgs~7.Exception = ~exception~5;
            
~PostSharp~Laos~Implementation.~aspect~1.OnException(~laosEventArgs~7);
            
switch (~laosEventArgs~7.FlowBehavior)
            {
                
case FlowBehavior.Continue:
                    
return ~returnValue~1;

                
case FlowBehavior.Return:
                    
return (bool~laosEventArgs~7.ReturnValue;
            }
            
throw;
        }
        
finally
        {
            
~laosEventArgs~7.ReturnValue = ~returnValue~1;
            
~PostSharp~Laos~Implementation.~aspect~1.OnExit(~laosEventArgs~7);
            
~returnValue~1 = (bool~laosEventArgs~7.ReturnValue;
        }
        
return ~returnValue~1;
    }

    [DebuggerNonUserCode]
    
public bool Delete(string id)
    {
        
bool ~returnValue~2;
        MethodExecutionEventArgs 
~laosEventArgs~8;
        
try
        {
            
object[] ~arguments~7 = new object[] { id };
            
~laosEventArgs~8 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this~arguments~7);
            
~PostSharp~Laos~Implementation.~aspect~2.OnEntry(~laosEventArgs~8);
            
if (~laosEventArgs~8.FlowBehavior == FlowBehavior.Return)
            {
                
return (bool~laosEventArgs~8.ReturnValue;
            }
            
try
            {
                Delegate delegateInstance 
= new ~PostSharp~Laos~Implementation.~delegate~0(this.~Delete);
                
object[] arguments = new object[] { id };
                MethodInvocationEventArgs eventArgs 
= new MethodInvocationEventArgs(delegateInstance, arguments);
                
~PostSharp~Laos~Implementation.~aspect~5.OnInvocation(eventArgs);
                
~returnValue~2 = (bool) eventArgs.ReturnValue;
            }
            
catch (Exception ~exception~3)
            {
                
object[] ~arguments~4 = new object[] { id };
                MethodExecutionEventArgs 
~laosEventArgs~5 = new MethodExecutionEventArgs(methodof(Orders.Delete, Orders), this~arguments~4);
                
~laosEventArgs~5.Exception = ~exception~3;
                
~PostSharp~Laos~Implementation.~aspect~4.OnException(~laosEventArgs~5);
                
switch (~laosEventArgs~5.FlowBehavior)
                {
                    
case FlowBehavior.Continue:
                        
goto Label_0160;

                    
case FlowBehavior.Return:
                        
~returnValue~2 = (bool~laosEventArgs~5.ReturnValue;
                        
goto Label_0160;
                }
                
throw;
            }
        Label_0160:
            
~laosEventArgs~8.ReturnValue = ~returnValue~2;
            
~PostSharp~Laos~Implementation.~aspect~2.OnSuccess(~laosEventArgs~8);
            
~returnValue~2 = (bool~laosEventArgs~8.ReturnValue;
        }
        
catch (Exception ~exception~6)
        {
            
~laosEventArgs~8.Exception = ~exception~6;
            
~PostSharp~Laos~Implementation.~aspect~2.OnException(~laosEventArgs~8);
            
switch (~laosEventArgs~8.FlowBehavior)
            {
                
case FlowBehavior.Continue:
                    
return ~returnValue~2;

                
case FlowBehavior.Return:
                    
return (bool~laosEventArgs~8.ReturnValue;
            }
            
throw;
        }
        
finally
        {
            
~laosEventArgs~8.ReturnValue = ~returnValue~2;
            
~PostSharp~Laos~Implementation.~aspect~2.OnExit(~laosEventArgs~8);
            
~returnValue~2 = (bool~laosEventArgs~8.ReturnValue;
        }
        
return ~returnValue~2;
    }

代码很简单,我是采用控制台应用实现的,如果您有兴趣,请 下载Demo源码玩玩。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值