首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 技術剖析(三十):以 RealProxy 實作服務呼叫 AOP 與通道生命週期自動管理

     編輯:關於.NET

本文承接上篇,展示如何使用 .NET Remoting 基礎設施中的 RealProxy/TransparentProxy 機制,實作一個通用的 WCF 服務代理工廠,自動處理通道建立、呼叫攔截、異常分類、通道關閉/中斷,徹底解決 ClientBase<T> 手動管理通道狀態易出錯、程式碼重複的問題。

問題背景

  • WCF 通道 (ICommunicationObject) 呼叫成功需 Close(),發生 CommunicationException 或 TimeoutException 需 Abort(),否則通道進入 Faulted 狀態導致後續呼叫失敗。
  • 標準模式需在每個呼叫點包裝 try/catch/finally,程式碼重複、易遺漏。

AOP 解決方案架構

順序圖流程:
Client → TransparentProxy (介面) → RealProxy.Invoke() → ChannelFactory.CreateChannel() → 真實呼叫 → 正常 Close / 異常 Abort → 回傳結果或拋出異常。

四步驟實作

步驟一:ChannelFactory 快取工廠


internal static class ChannelFactoryCreator {
  private static Hashtable channelFactories = new Hashtable();
  public static ChannelFactory Create(string endpointName) {
    if (string.IsNullOrEmpty(endpointName)) throw new ArgumentNullException("endpointName");
    ChannelFactory cf = null;
    if (channelFactories.ContainsKey(endpointName))
      cf = channelFactories[endpointName] as ChannelFactory;
    if (cf == null) {
      cf = new ChannelFactory(endpointName);
      lock (channelFactories.SyncRoot) channelFactories[endpointName] = cf;
    }
    return cf;
  }
}

以端點組態名稱為 Key 快取 ChannelFactory<T>,避免重複建立開銷。

步驟二:自訂 RealProxy


public class ServiceRealProxy : RealProxy {
  private string _endpointName;
  public ServiceRealProxy(string endpointName) : base(typeof(T)) {
    _endpointName = endpointName;
  }
  public override IMessage Invoke(IMessage msg) {
    var channel = ChannelFactoryCreator.Create(_endpointName).CreateChannel();
    var call = (IMethodCallMessage)msg;
    var args = call.Args; // 參數陣列
    IMethodReturnMessage ret;
    try {
      var result = call.MethodBase.Invoke(channel, args);
      ret = new ReturnMessage(result, args, args.Length, call.LogicalCallContext, call);
      ((ICommunicationObject)channel).Close();
    } catch (Exception ex) {
      if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)
        ((ICommunicationObject)channel).Abort();
      ret = new ReturnMessage(ex.InnerException ?? ex, call);
    }
    return ret;
  }
}

步驟三:服務代理靜態工廠


public static class ServiceProxyFactory {
  public static T Create(string endpointName) {
    if (string.IsNullOrEmpty(endpointName)) throw new ArgumentNullException("endpointName");
    return (T)new ServiceRealProxy(endpointName).GetTransparentProxy();
  }
}

步驟四:客戶端呼叫


var calc = ServiceProxyFactory.Create("calculatorservice");
for (int i=1; i<2000; i++)
  Console.WriteLine("{0}: x+y={1}", i, calc.Add(1,2)); // 2000 次呼叫,每次自動 Close

// 異常不影響後續呼叫示範
try { calc.Divide(2,0); } catch {}
Console.WriteLine("After fault: " + calc.Add(2,0)); // 正常執行,因前一次已 Abort

執行結果驗證

  • 2000 次迴圈呼叫全部成功,證明每次通道皆正確關閉。
  • 故意觸發除零異常 (伺服器端拋出),通道 Abort,後續呼叫不受影響,證明隔離性。

已知限制與擴充方向

  • 未處理安全認證 (ClientCredentials)、雙工回調 (DuplexChannelFactory)、OperationContextScope 流程。
  • 快取 Key 僅用端點名稱,未區分 Binding/Address/Callback 差異 (可擴充為 Tuple Key)。
  • 可整合 IExtension<IContextChannel> 實作自訂訊息檢查器、記錄器。
  • 生產環境建議加入記憶體洩漏偵測 (定期清理閒置 Factory)。

核心價值

將横切關注點 (通道生命週期、異常處理、效能快取) 封裝於 RealProxy 內部,客戶端程式碼回歸純粹的業務介面呼叫,實現 Reuse 而非 Duplicate 的設計原則。

此模式同樣適用於 gRPC、Web API、命名管道等任何具備「連線建立/關閉/異常中斷」語意的 RPC 框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved