WCF客戶端運行時架構體係詳解[下篇]
當基於某個終結點創建的ChannelFactory<TChannel>被開啟的之後,位於服務模型層的客戶端運行時框架被成功構建。站在編程的角度看ChannelFactory<TChannel>,它就是一個創建用於服務調用的服務代理對象的工廠。由於服務調用需要借助於服務代理來完成,我們很有必要從整個客戶端運行架構層麵來了解服務代理和基於服務代理的服務調用是如何實現的。
目錄
一、服務代理是一個透明代理
二、服務調用的流程
操作選擇
輸入參數檢驗
序列化請求消息
請求消息的發送和回複消息的接收
回複消息的檢驗
反序列化回複消息
檢驗返回值(或者ref/out參數)
如果你閱讀了《WCF技術剖析(卷1)》第8章《客戶端(Client)》,你應該知道通過ChannelFactory<TChannel>創建的服務代理對象是一個“透明代理(Transparent Proxy)”對象。而這可以通過調用RemotingServices的靜態方法IsTransparentProxy來檢驗。為此我寫了如下一段簡單的檢驗程序,而輸出的結果證實了“服務代理是透明代理”的結論。
1: using (ChannelFactory<ICalculate> channelFactory = new ChannelFactory<ICalculate>("calculateservice"))
2: {
3: ICalculate calculator = channelFactory.CreateChannel();
4: bool isTransparentProxy = RemotingServices.IsTransparentProxy(calculator);
5: Console.WriteLine("Service porxy is a transparent proxy? {0}.", isTransparentProxy ? "Yes" : "No");
6: }
輸出結果:
1: Service porxy is a transparent proxy? Yes.
既然服務代理是一個透明代理,它一定對應了具體的真實代理(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參數對象進行檢驗。
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-26 16:04:34