本文承接上篇,展示如何使用 .NET Remoting 基礎設施中的 RealProxy/TransparentProxy 機制,實作一個通用的 WCF 服務代理工廠,自動處理通道建立、呼叫攔截、異常分類、通道關閉/中斷,徹底解決 ClientBase<T> 手動管理通道狀態易出錯、程式碼重複的問題。
ICommunicationObject) 呼叫成功需 Close(),發生 CommunicationException 或 TimeoutException 需 Abort(),否則通道進入 Faulted 狀態導致後續呼叫失敗。try/catch/finally,程式碼重複、易遺漏。順序圖流程:
Client → TransparentProxy (介面) → RealProxy.Invoke() → ChannelFactory.CreateChannel() → 真實呼叫 → 正常 Close / 異常 Abort → 回傳結果或拋出異常。
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>,避免重複建立開銷。
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
Abort,後續呼叫不受影響,證明隔離性。ClientCredentials)、雙工回調 (DuplexChannelFactory)、OperationContextScope 流程。IExtension<IContextChannel> 實作自訂訊息檢查器、記錄器。將横切關注點 (通道生命週期、異常處理、效能快取) 封裝於 RealProxy 內部,客戶端程式碼回歸純粹的業務介面呼叫,實現 Reuse 而非 Duplicate 的設計原則。
此模式同樣適用於 gRPC、Web API、命名管道等任何具備「連線建立/關閉/異常中斷」語意的 RPC 框架。