傳統的AOP並不需要用戶端做代碼結構的變更,最多也就是配置上的問題。但在.net中要想實現AOP,我想最方便的實現機制要屬代理機制了,但只要利用代理,在性能上就會造成一定的影響。
如果開發過分散式服務,像remotion,wcf等,消息都是它們通信的重要手段。用戶端通過方法調用形式體現的服務訪問需要轉換成具體的消息,然後經過編碼才能利用傳輸通道發送給服務端,服務執行的結果也只能以消息的形式返回給調用方。
這些分散式服務有一共同特點:都通過代理方法間接的調用服務。服務代理,它自身並不提供服務的實現,只是起到一個仲介作用,用戶端把服務要求傳送給服務代理,服務代理再去調真正的服務,同樣服務返回時,也是返回給服務代理,再由服務代理返回給用戶端。看到這,我想對於實現AOP的攔截就有點眉目了。在.net中,我們可以寫自訂的RealProxy來實現AOP的方法攔截功能。
服務代理通常又分為以下兩種:

 

1:透明代理。用戶端在跨任何類型的遠端處理邊界使用物件時,對物件使用的實際上是透明代理。透明代理使人以為實際物件駐留在用戶端空間中。它實現這一點的方法是:使用遠端處理基礎結構將對其進行的調用轉發給真實物件。透明代理本身由 RealProxy 類型的託管運行時類的實例收容。RealProxy 實現從透明代理轉發操作所需的部分功能。代理物件繼承託管物件(例如垃圾回收、對成員和方法的支援)的關聯語義,可以將其進行擴展以形成新類。這樣,該代理具有雙重性質,一方面,它需要充當與遠端物件(透明代理)相同的類的物件;另一方面,它本身是託管物件。
2:真實代理。RealProxy來實現與遠端服務進行通信,所以這裡就是我們實現AOP的地方。

 

下圖是透明代理與真實代理以及遠端物件的調用關係圖:

0925442934-0  

下圖是利用自訂的RealProxy實現AOP方法攔截的原理圖:

09254450M-1  

自訂異常代理類:
說明:1>自訂的代理類需要繼承RealProxy。
2>從 RealProxy 繼承時,必須重寫 Invoke方法。
3>下面代碼中的LogManage是一個log4net介面,我們可以把異常統一記錄到日誌中,供日後分析。
代碼
/// <summary>
/// Aspect代理,在這個類裡面,實現對方法的攔截
/// </summary>
public class AspectProxyErrorLog : RealProxy
{
AspectManagedAttribute attr;
/// <summary>
/// 預設建構函式
/// </summary>
public AspectProxyErrorLog() : base()
{
}
/// <summary>
/// 建構函式
/// </summary>
/// <param name="myType">被代理的類的類型</param>
public AspectProxyErrorLog(Type myType) : base(myType)
{
}
/// <summary>
/// 建構函式
/// </summary>
/// <param name="myType">被代理的類的類型</param>
/// <param name="obj">被代理的物件</param>
public AspectProxyErrorLog(Type myType,MarshalByRefObject obj) : base(myType)
{
target=obj;
}
MarshalByRefObject target;
ILog LogManage;
/// <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 != ex.InnerException)
{
methodReturn = new ReturnMessage(ex.InnerException, methodCall);
}
else
{
methodReturn = new ReturnMessage(ex, methodCall);
}
}
retMsg = methodReturn;

 

}
if (null != methodReturn)
{
if (null != methodReturn.Exception )
{
if (null != this.LogManage )
{
this.LogManage.Error(ceha .MethodErrorText + methodReturn.Exception.ToString());
}

 

}
}
return retMsg;

 

}
} 上面只是貼了部分代碼,在下一篇中,我會對這部分代碼做更加詳細的分析。

 

作者:姜敏
出處:HTTP://www.cnblogs.com/aspnet2008/
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()