.net中实现AOP(二)

    上篇文章我大概说了一下在.net中如何利用自定义代理类来实现AOP,那篇文章主要说了些原理,这篇我们直接上代码。

 

     第一:AspectManagedAttribute特性。说到代理机制,那么它直接针对的应该是一个类而不是具体的方法,所以这里我们实现AOP的最小单位就是类,我们定义一个AspectManagedAttribute特性,它标识了具体类会受到AOP管理。
   
     说明:
    
        1:由于这个特性允许标识在类上,所在需要加上[AttributeUsage(AttributeTargets.Class)]。

        2:AOP可以实现多种非业务逻辑的"横切点",这里我们给AspectManagedAttribute增加一个枚举AspectManagedType,这里分为两种:

           1》:普通的异常捕获,当请求的方法抛出异常时,记录在日志中,同时返回空对象。
           2》:在普通异常捕获的基础上,增加方法调用的时间记录。 

public   enum  AspectManagedType
    {
        ErrorHandle,
        ElapsedTime
    }
      

         3》:继承ProxyAttribute:指示对象类型需要自定义代理。

         4》:重写ProxyAttribute的方法:MarshalByRefObject CreateInstance(Type serverType)。根据不同的AspectManagedType创建不同的自定义代理类。
        

ExpandedBlockStart.gif 代码
public   override  MarshalByRefObject CreateInstance(Type serverType)
        {
            MarshalByRefObject mobj 
=   base .CreateInstance(serverType);
            
if  (aspectManaged)
            {
                RealProxy realProxy 
=   this  .GetCurrentRealProxy  ( this .aspectManagedType , serverType, mobj);
                MarshalByRefObject retobj 
=  realProxy.GetTransparentProxy()  as  MarshalByRefObject;
                
return  retobj;
            }
            
else
            {
                
return  mobj;
            }

        }
        
private  RealProxy GetCurrentRealProxy(AspectManagedType _aspectManagedType, Type serverType, MarshalByRefObject mobj)
        {
            RealProxy real 
=   null ;
            
if  (AspectsManager.AspectsProxy.ContainsKey(serverType.Name))
            {
                
return  AspectsManager.AspectsProxy[serverType.Name];
            }
            
switch  (_aspectManagedType)
            {
                
case  AspectManagedType .ElapsedTime :
                    real 
=   new  AspectProxyElapsedTime(serverType, mobj);
                    
break ;
                
case  AspectManagedType.ErrorHandle :
                    real 
=   new  AspectProxyErrorLog(serverType, mobj);
                    
break ;
                
default  :
                    real 
=   new  AspectProxyErrorLog(serverType, mobj);
                    
break ;
            }
            
lock  (AspectsManager.AspectsProxy)
            {
                AspectsManager.AspectsProxy.Add(serverType.Name, real);
            }
            
return  real;
        }
  

 

        5:把所有的CustomProxy放入静态变量中,有小小的性能提升。这里我们创建了AspectsManager,代码比较简单,只包含一个管理器容器。
    

public    class  AspectsManager
 {
  
public    static  Dictionary < string  , RealProxy >  AspectsProxy  =   new  Dictionary < string  , RealProxy > ();
 } 

 

      第二:自定义代理类的实现,这里我就贴异常处理的AspectProxyErrorLog:

      说明:
  
        1:需要继承RealProxy,它提供代理的基本功能。 
        2:重写RealProxy的IMessage Invoke(IMessage msg),对当前实例所表示的远程对象调用在所提供的 IMessage 中指定的方法。

       

ExpandedBlockStart.gif 代码
  ///   <summary>
  
///  当在派生类中重写时,在当前实例所表示的远程对象上调用在所提供的 IMessage 中指定的方法。 <br />
  
///  WebsharpAspect在这里执行对方法执行的拦截处理
  
///   </summary>
  
///   <param name="msg"> IMessage,包含有关方法调用的信息。 </param>
  
///   <returns> 调用的方法所返回的消息,包含返回值和所有 out 或 ref 参数。 </returns>
   public   override  IMessage Invoke(IMessage msg)
  {
   IMessage retMsg
= null  ;
            IMethodCallMessage methodCall 
=  (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn 
=   null ;
            
object [] copiedArgs  =  Array.CreateInstance( typeof ( object ), methodCall.Args.Length)  as   object [];
            methodCall.Args.CopyTo(copiedArgs, 
0 );
            
object [] attrs  =   null ;
            CoustomerErrorHandleAttribute ceha 
=   null ;
            
if  (msg  is  IConstructionCallMessage)
            {
                IConstructionCallMessage ccm 
=  (IConstructionCallMessage)msg;
                RemotingServices.GetRealProxy(target).InitializeServerObject(ccm);
                ObjRef oRef 
=  RemotingServices.Marshal(target);
                RemotingServices.Unmarshal(oRef);
                retMsg 
=  EnterpriseServicesHelper.CreateConstructionReturnMessage(ccm, (MarshalByRefObject) this .GetTransparentProxy());
            }
            
else
            {
                IMethodCallMessage mcm 
=  (IMethodCallMessage)msg;                
                attrs 
=  methodCall.MethodBase.GetCustomAttributes( typeof (CoustomerErrorHandleAttribute),  false );               
                ceha 
=  LogManagerFactory.GetCoustomerErrorHandleAttribute(attrs, methodCall.MethodBase.Name );
                
if  ( null   !=  ceha)
                {
                    LogManage 
=  ceha.ILogName;
                }
                
try
                {
                    
object  returnValue  =  methodCall.MethodBase.Invoke( this .target, copiedArgs);
                    methodReturn 
=   new  ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                    
                }
                
catch  (Exception ex)
                {
                    
if  ( null   !=   this .LogManage)
                    {
                        
this .LogManage.Error(ceha.MethodErrorText  +  ex.ToString());
                    }
                    methodReturn 
=   new  ReturnMessage( null , methodCall);
                }
                retMsg 
=  methodReturn;
            }
   
return  retMsg;
  }

      

          3:当捕获到异常后,首先将异常信息写入日志,为了让方法不对外抛出异常,我们可以对返回信息做处理,让它直接返回null。不知道这样做是否妥当,大家多多提意见啊。

   

     第三:.net中要想实现方法的捕获,当然少不了ContextBoundObject:定义所有上下文绑定类的基类。这里我们可以创建一个空类,然后继承ContextBoundObject,客户端的类只需要做下继承就行。
 

public   abstract   class  AspectObject  : ContextBoundObject
 {
 }

    
      第四:客户端调用。
     
           1:

[AspectManaged(aspectManagedType = AspectManagedType.ErrorHandle  )]
public   class  GetMemberInfoProxy : AspectObject 

 

           2:如果项目比较多,我们希望把日志能记录到不同的位置,往往我们会创建多个ILog接口,这里可以在方法上下手,创建一个方法级的CoustomerErrorHandle。主要提供如下几个属性:

              1>:public ILog ILogName { get; set; } 提供自定义的日志接口。当然ILog不能体现在Atttribute中,我们可以采用枚举来替换,然后在后端来动态创建ILog接口。
              2>:public string MethodElapsedTimeText { get; set; }  方法耗时的提示语。当此参数没有时,默认为方法名。
              3>: public string MethodErrorText { get; set; } 方法出异常时的提示语。当此参数没有时,默认为方法名。

           3:方法级的示例:

[CoustomerErrorHandle(MethodElapsedTimeText  =   " 根据会员卡号读取会员信息用时: " , MethodErrorText  =   " 根据会员卡号读取会员信息异常: " )]
public  MemberInfo GetMemberInfo( long   cardNo)

 

      总结:

            本人对本篇文章的AOP做了下性能测试,没发现多大的消耗,大家对AOP性能有啥看法,多多指教。

 


作者:姜敏
出处:http://www.cnblogs.com/aspnet2008/ 

 

 

转载于:https://www.cnblogs.com/ASPNET2008/archive/2010/04/26/1721558.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值