WCF客戶端運行時架構體系詳解[下篇]
當基于某個終結點創建的ChannelFactory<TChannel>被開啟的之后,位于服務模型層的客戶端運行時框架被成功構建。站在編程的角度看ChannelFactory<TChannel>,它就是一個創建用于服務調用的服務代理對象的工廠。由于服務調用需要借助于服務代理來完成,我們很有必要從整個客戶端運行架構層面來了解服務代理和基于服務代理的服務調用是如何實現的。
目錄
一、服務代理是一個透明代理
二、服務調用的流程
操作選擇
輸入參數檢驗
序列化請求消息
請求消息的發送和回復消息的接收
回復消息的檢驗
反序列化回復消息
檢驗返回值(或者ref/out參數)
一、服務代理是一個透明代理
如果你閱讀了《WCF技術剖析(卷1)》第8章《客戶端(Client)》,你應該知道通過ChannelFactory<TChannel>創建的服務代理對象是一個“透明代理(Transparent Proxy)”對象。而這可以通過調用RemotingServices的靜態方法IsTransparentProxy來檢驗。為此我寫了如下一段簡單的檢驗程序,而輸出的結果證實了“服務代理是透明代理”的結論。
{
ICalculate calculator = channelFactory.CreateChannel();
bool isTransparentProxy = RemotingServices.IsTransparentProxy(calculator);
Console.WriteLine("Service porxy is a transparent proxy? {0}.", isTransparentProxy ?"Yes" : "No");
}
輸出結果:
既然服務代理是一個透明代理,它一定對應了具體的真實代理(RealProxy)。實際上,服務代理對象內部具有一個類型為ServiceChannelProxy的對象作為其真實代理對象。ServiceChannelProxy是WCF中的一個繼承自RealProxy的類型,而其核心則是一個類型為ServiceChannel的對象。ServiceChannelProxy和ServiceChannel均是定義在System.ServiceModel.Channels命名空間下的內部(Internal)類型。
當我們使用ChannelFactory<TChannel>創建一個服務代理的時候,WCF會根據代表客戶端運行時的ClientRuntime創建一個ServiceChannel對象。并且調用之前創建的信道工廠棧并最終創建信道棧。由于ServiceChannel同時引用著代表服務模型層核心的ClientRuntime和信道層的信道棧,所以我們可以說ServiceChannel是連接WCF客戶端服務模型層與信道層之間的紐帶。當ServiceChannel被成功創建后,WCF會基于該對象創建ServiceChannelProxy對象。最然返回這個真實代理對象的透明代理。
當我們通過顯式(將服務代理對象轉換成ICommunicationObject類型,并顯式調用其Open方法)或者隱式(如果服務代理在未開啟的狀態下被用于服務調用,在進行服務調用之前會被隱式地開啟)開啟時,整個信道棧會被開啟。下圖揭示了服務代理(透明代理)、ServiceChannelProxy(真實代理)、ServiceChannel、ClientRuntime和信道棧之間的關系。
由于服務代理是一個透明代理,所以針對它的任何一個方法調用都會最終轉換到對其真實代理(ServiceChannelProxy)的Invoke方法的調用。所以ServiceChannelProxy會接管所有針對于服務代理對象的服務調用,并最終將調用遞交給內部的ServiceChannel處理。
接下來,我們來簡單地介紹一下針對一次簡單的針對服務代理的服務調用,ServiceChannel在其內部是按照怎樣的流程來處理的。實際上,相同的內容已經出現在了《WCF技術剖析(卷1)》第8章《客戶端(Client)》中。下面的列表體現了ServiceChannel進行服務調用的整個流程(以請求/回復消息交換模式為例)。
操作選擇
如果當前ClientRuntime的OperationSelector屬性具有一個操作選擇器,則調用其SelectOperation方法或者針對當前服務調用的客戶端操作;
輸入參數檢驗
遍歷當前ClientRuntime的ParameterInspectors屬性表示的參數檢驗器列表,調用其BeforeCall方法對輸入參數實施檢驗;
序列化請求消息
通過當前ClientOperation的SerializeRequest屬性判斷是否需要進行請求消息的序列化。如果需要,則根據當前ClientOperation的Formatter屬性獲取消息格式化器,最終調用SerializeRequest方法將以方法調用形式體現的服務調用序列化成請求消息。
請求消息檢驗
遍歷以當前ClientOperation的MessageInspectors屬性表示的消息檢驗器列表,并調用BeforeSendRequest方法對請求消息實施發送前的檢驗。
請求消息的發送和回復消息的接收
將請求消息遞交給信道層進行進一步處理,經過編碼后的請求消息通過傳輸信道發送到服務端并等待回復。當回復消息抵達客戶端后,信道層對其進行接收、解碼相應的處理。
回復消息的檢驗
遍歷以當前ClientOperation的MessageInspectors屬性表示的消息檢驗器列表,并調用AfterReceiveReply方法對回復消息實施發送前的檢驗。
反序列化回復消息
通過當前ClientOperation的DeserializeReply屬性判斷是否需要進行回復消息的反序列化。如果需要,則根據當前ClientOperation的Formatter屬性獲取消息格式化器,最終調用DeserializeReply方法將包含在回復消息的調用結果反序列化成方法調用的返回值或者ref/out參數對象。
檢驗返回值(或者ref/out參數)
遍歷當前ClientRuntime的ParameterInspectors屬性表示的參數檢驗器列表,調用其AfterCall方法對返回值或者ref/out參數對象進行檢驗。