閱讀361 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《WCF技術剖析》博文係列匯總[持續更新中]

近半年以來,一直忙於我的第一本WCF專著《WCF技術剖析(卷1)》的寫作,一直無暇管理自己的Blog。在《WCF技術剖析(卷1)》寫作期間,對WCF又有了新的感悟,為此以書名開始本人的第三個WCF係列。本係列的目的在於對《WCF技術剖析》的補充,會對書中的一些內容進行展開講述,同時會囊括很多由於篇幅的原因忍痛割棄的內容。

[第1篇] 通過一個ASP.NET程序模擬WCF基礎架構

本係列的第一篇,我將會對WCF的基本架構作一個大致的講解。不過,一改傳統對WCF的工作流程進行平鋪直敘,我將另辟蹊徑,借助於我們熟悉的ASP.NET作為請求處理平台,通過一個簡單的托管程序模擬整個WCF客戶端和服務端的架構。源代碼從這裏下載。

[第2篇] 再談IIS與ASP.NET管道

在2007年9月份,我曾經寫了三篇詳細介紹IIS架構和ASP.NET運行時管道的文章,深入介紹了IIS 5.x與IIS 6.0HTTP請求的監聽與分發機製,以及ASP.NET運行時管道對HTTP請求的處理流程:《IIS和ASP.NET ISAPI》、《ASP.NET運行時管道[上篇][下篇]》很多人留言為何沒有IIS 7的介紹。在寫作《WCF技術剖析(卷1)》中,為了剖析基於IIS的WCF服務寄宿(Hosting),再次對相關內容進行了研究,在這裏一並與大家分享。

[第3篇] 如何進行基於非HTTP的IIS服務寄宿

在介紹IIS7.0的時候,我們談到,HTTP.SYS+W3SVC實現了基於HTTP的請求監聽,在此基礎上引入了以下三組網絡監聽器(Listener)和監聽適配器(Adapter),實現了基於TCP、Named Pipes和MSMQ的網絡監聽。TCPListener|TCP Listener Adapter、NamedPipes Listener|Named Pipes Listener Adapter、MSMQ Listener|MSMQ Listener Adapter。由於IIS 7提供了基於非HTTP網絡協議的監聽支持,那麼就意味著當我們當我們通過IIS進行WCF服務寄宿(Hosting)的時候,可以采用非HTTP的通信方式。在本篇文章中,我們將通過一個簡單實例介紹進行非HTTP的IIS服務寄宿,源代碼從這裏下載。

[第4篇] 基於IIS的WCF服務寄宿(Hosting)實現揭秘

通過《再談IIS與ASP.NET管道》的介紹,相信讀者已經對IIS和ASP.NET的請求處理管道有了一個大致的了解,在此基礎上去理解基於IIS服務寄宿的實現機製就顯得相對容易了。概括地說,基於IIS的服務寄宿依賴於兩個重要的對象:System.ServiceModel.Activation.HttpModuleSystem. ServiceModel.Activation.HttpHandler

[第5篇] 利用ASP.NET兼容模式創建支持會話(Session)的WCF服務

在《基於IIS的WCF服務寄宿(Hosting)實現揭秘》中,我們談到在采用基於IIS(或者說基於ASP.NET)的WCF服務寄宿中,具有兩種截然不同的運行模式:ASP.NET並行(Side by Side)模式和ASP.NET兼容模式。對於前者,WCF通過HttpModule實現了服務的寄宿,而對於後者,WCF的服務寄宿通過一個 HttpHandler實現。隻有在ASP.NET兼容模式下,我們熟悉的一些ASP.NET機製才能被我們使用,比如通過HttpContext的請求下下文;基於文件或者Url的授權;HttpModule擴展;身份模擬(Impersonation)等。

由於在ASP.NET兼容模式下,ASP.NET采用與.aspx Page完全一樣的方式處理基於.svc的請求,換言之,我們就可以借助當前HttpContext的SessionState維護會話狀態,進而創建一個支持會話的WCF Service。接下來,我們就通過一個簡單的例子,一步步地創建這樣的會話服務。

[第6篇] 為什麼在基於ASP.NET應用寄宿(Hosting)下配置的BaseAddress無效

本篇文章來源於幾天前一個朋友向我谘詢的問題。問題是這樣的,他說他采用ASP.NET應用程序的方式對定義的WCF服務進行寄宿(Hosting),並使用配置的方式對服務的BaseAddress進行了設置,但是在創建ServiceHost的時候卻拋出 InvalidOperationException,並提示相應Address Scheme的BaseAddress找不到。我意識到這可能和WCF中用於判斷服務寄宿方式的邏輯有關,於是我讓這位朋友將相同的服務寄宿代碼和配置遷移到GUI程序或者Console應用中,看看是否正常。結果如我所想,一切正常,個人覺得這應該是WCF的一個Bug。今天撰文與大家討論,看看大家對這個問題有何見解。

[第7篇] 如何實現WCF與EnterLib PIAB、Unity之間的集成

在這之前,我寫過深入介紹MS EnterLib PIAB的文章(參閱《MS Enterprise Library Policy Injection Application Block 深入解析[總結篇]》),也寫過WCF與PIAB的集成(參閱:《WCF後續之旅(8):通過WCF Extension 實現與MS Enterprise Library Policy Injection Application Block 的集成》)、WCF與Unity的集成(參閱《WCF後續之旅(7):通過WCF Extension實現和Enterprise Library Unity Container的集成》)以及Unity與PIAB的集成(參閱《Enterprise Library深入解析與靈活應用(1):通過Unity Extension實現和Policy Injection Application Block的集成》、《Enterprise Library深入解析與靈活應用(7):再談PIAB與Unity之間的集成》)。由於部分實現時基於EnterLib、Unity前一個版本,在新的版本中(EnterLib V4.1與Unity 1.2)中,MS通過Unity對PIAB進行了重新設計與實現,所以我們很有必要重拾著這個話題,談談對於新的EnterLib和Unity,如何將 PIAB和Unity集成到WCF之中。(Source Code從這裏下載)

[第8篇] ClientBase<T>中對ChannelFactory<T>的緩存機製

和傳統的分布式遠程調用一樣,WCF的服務調用借助於服務代理(Service Proxy)。而ChannelFactory<T>則是服務代理的創建者。WCF采用基於終結點(Endpoint)服務消費方式:WCF 服務通過一個或者多個終結點暴露給潛在的服務消費者,服務的消費中通過與之匹配的終結點與之交互。在客戶端,我們具有兩種典型的服務代理創建方式,其一是通過諸如SvcUtil.exe這樣的工具導入服務的元數據生成相應的服務代理(一個繼承自ClientBase<T>的類型)代碼和相關配置;其二是直接通過相應的終結點信息(通過代碼指定或者配置)創建ChannelFactory<T>對象,並借助該對象直接進行服務代理的創建。

實際上,即使通過ClientBase<T>對象進行服務調用,其內部也是調用 ChannelFactory<T>創建的服務代理。整個ChannelFactory<T>的創建是一項相對複雜並且費時的工作,會涉及很多諸如反射、配置文件的讀取等操作。為了提高服務調用的性能,在.NET 3.5中,WCF在ClientBase<T>中引入了ChannelFactory<T>的緩存機製。

[第9篇] 服務代理不能得到及時關閉會有什麼後果?

我們想對WCF具有一定了解的人都會知道:在客戶端通過服務調用進行服務調用過程中,服務代理應該及時關閉。但是如果服務的代理不等得到及時的關閉,到底具有怎樣的後果?什麼要關閉服務代理?在任何時候都需要關閉服務代理嗎?是否有一些例外呢?本篇文章將會圍繞著這些問題展開。

[第10篇] 調用WCF服務的客戶端應該如何進行異常處理

在前麵一片文章(服務代理不能得到及時關閉會有什麼後果?)中,我們談到及時關閉服務代理(Service Proxy)在一個高並發環境下的重要意義,並闡明了其根本原因。但是,是否直接調用ICommunicationObject的Close方法將服務代理關閉就萬事大吉了呢?事情遠不會這麼簡單,這其中還會涉及關於異常處理的一些操作,這就是本篇文章需要討論的話題。

[第11篇] 異步操作在WCF中的應用[上篇][下篇]

按照操作執行所需的資源類型,我們可以將操作分為CPU綁定型(CPU Bound)操作和I/O綁定型(I/O Bound)操作。對於前者,操作的執行主要利用CPU進行密集的計算,而對於後者,大部分的操作處理時間花在I/O操作處理,比如訪問數據庫、文件係統、網絡資源等。對於I/O綁定型操作,我們可以充分利用多線程的機製,讓多個操作在自己的線程並發執行,從而提高係統性能和響應能力。服務調用就是典型的I/O綁定型操作,所以多線程在服務調用中具有廣泛的應用。在本篇文章中,我們專門來討論多線程或者是異步操作在WCF中的具體應用。

[第12篇] 數據契約(Data Contract)和數據契約序列化器(DataContractSerializer)

大部分的係統都是以數據為中心的(Data Central),功能的實現表現在對相關數據的正確處理。而數據本身,是有效信息的載體,在不同的環境具有不同的表示。一個分布式的互聯係統關注於數據的交換,而數據正常交換的根本前提是參與數據交換的雙方對於數據結構的一致性理解。這就為數據的表現提出了要求,為了保證處於不同平台、不同廠商的應用能夠正常地進行數據交換,交換的數據必須采用一種大家都能夠理解的展現方式。在這方麵,XML無疑是最好的選擇。所以WCF下的序列化(Serialization)解決的就是如何將數據從對象的表現形式轉變成XML表現形式,以確保數據的正常交換。

[第13篇] 序列化過程中的已知類型(Known Type)

DataContractSerializer承載著所有數據契約對象的序列化和反序列化操作。在上麵一篇文章(《數據契約(Data Contract)和數據契約序列化器(DataContractSerializer)》)中,我們談到DataContractSerializer基本的序列化規則;如何控製DataContractSerializer序列化或者反序列化對象的數量;以及如何在序列化後的XML中保存被序列化對象的對象引用結構。在這篇文章中,我們會詳細討論WCF序列化中一個重要的話題:已知類型(Known Type)。

WCF下的序列化與反序列化解決的是數據在兩種狀態之間的相互轉化:托管類型對象和XML。由於類型定義了對象的數據結構,所以無論對於序列化還是反序列化,都必須事先確定對象的類型。如果被序列化對象或者被反序列化生成的對象包含不可知的類型,序列化或者反序列化將會失敗。為了確保DataContractSerializer的正常序列化和反序列化,我們需要將“未知”類型加入 DataContractSerializer“已知”類型列表中。

[第14篇] 泛型數據契約和集合數據契約[上篇][下篇]

在.NET Framework 2.0中,泛型第一次被引入。我們可以定義泛型接口、泛型類型、泛型委托和泛型方法。序列化依賴於真實具體的類型,而泛型則刻意模煳了具體類型概念。而集合代表一組對象的組合,集合具有可迭代(Enumerable)的特性,可以通過某個迭代規則遍曆集合中的每一個元素。由於範型類型和集合類型在序列化和反序列化上具有一些特殊的行為和規則,在這篇文章中,我將會對此進行詳細介紹。

[第15篇] 數據契約代理(DataContractSurrogate)在序列化中的作用

如果一個類型,不一定是數據契約,和給定的數據契約具有很大的差異,而我們要將該類型的對象序列化成基於數據契約對應的XML。反之,對於一段給定的基於數據契約的XML,要通過反序列化生成該類型的對象,我們該如何實現這樣的場景?

[第16篇] 數據契約的等效性和版本控製

數據契約是對用於交換的數據結構的描述,是數據序列化和反序列化的依據。在一個WCF應用中,客戶端和服務端必須通過等效的數據契約方能進行有效的數據交換。隨著時間的推移,不可避免地,我們會麵臨著數據契約版本的變化,比如數據成員的添加和刪除、成員名稱或者命名空間的修正等,如何避免數據契約這種版本的變化對客戶端現有程序造成影響,就是本節著重要討論的問題。

[第17篇] 消息(Message)詳解[上篇][中篇][下篇]

消息交換是WCF進行通信的唯一手段,通過方法調用(Method Call)形式體現的服務訪問需要轉化成具體的消息,並通過相應的編碼(Encoding)才能通過傳輸通道發送到服務端;服務操作執行的結果也隻能以消息的形式才能被正常地返回到客戶端。所以,消息在整個WCF體係結構中處於一個核心的地位,WCF可以看成是一個消息處理的管道。

盡管消息在整個WCF體係中具有如此重要的意義,可是一般的WCF編程人員,卻意識不到消息的存在。原因很簡單,WCF設計的目標就是實現消息通信的所有細節,為最終的編程人員提供一個完全麵向對象的編程模型。所以對於一般的編程人員來說,他們麵對的是接口,卻不知道服務契約對於服務的描述;麵對的是數據類型,卻不知道數據契約對序列化的作用;麵對的是方法調用和返回值的獲取,卻不了解底層消息交換的過程。

鼓勵大家深入了解WCF關於消息處理的流程具有兩個目的:第一,隻有在對整個消息處理流程具有清晰認識的基礎上才能寫出高質量的WCF程序。第二,WCF是一個極具可擴展性的通信框架,可以靈活地創建一些自定義WCF擴展(WCF Extension)以實現你所需要的功能。如同WCF的插件一樣,這些自定義的WCF擴展以即插即用的方式參與到WCF整個消息處理流程之中。了解 WCF整個消息處理流程是靈活進行WCF擴展的前提。

[第18篇] 消息契約(Message Contract)和基於消息契約的序列化

在本篇文章中,我們將討論WCF四大契約(服務契約、數據契約、消息契約和錯誤契約)之一的消息契約(Message Contract)。服務契約關注於對服務操作的描述,數據契約關注於對於數據結構和格式的描述,而消息契約關注的是類型成員與消息元素的匹配關係。

我們知道隻有可序列化的對象才能通過服務調用在客戶端和服務端之間進行傳遞。到目前為止,我們知道的可序列化類型有兩種:一種是應用了System.SerializableAttribute特性或者實現了System.Runtime.Serialization.ISerializable接口的類型;另一種是數據契約對象。對於基於這兩種類型的服務操作,客戶端通過System.ServiceModel.Dispatcher.IClientMessageFormatter將輸入參數格式化成請求消息,輸入參數全部內容作為有效負載置於消息的主體中;同樣地,服務操作的執行結果被System.ServiceModel.Dispatcher.IDispatchMessageFormatter序列化後作為回複消息的主體。

在一些情況下,具有這樣的要求:當序列化一個對象並生成消息的時候,希望將部分數據成員作為SOAP的報頭,部分作為消息的主體。比如說,我們有一個服務操作采用流的方式進行文件的上載,除了以流的方式傳輸以二進製表示的文件內容外,還需要傳輸一個額外的基於文件屬性的信息,比如文件格式、文件大小等。一般的做法是將傳輸文件內容的流作為SOAP的主體,將其屬性內容作為SOAP的報頭進行傳遞。這樣的功能,可以通過定義消息契約來實現。

[第19篇] 深度剖析消息編碼(Encoding)實現[上篇][下篇]

消息作為WCF進行通信的唯一媒介,最終需要通過寫入傳輸層進行傳遞。而對消息進行傳輸的一個前提或者是一項必不可少的工作是對消息進行相應的編碼。WCF 提供了一係列可供選擇的編碼方式,它們分別在互操作和性能各具優勢。在本篇文章我們將對各種編碼方式進行消息的討論。

從互操作性的角度來看,編碼方法很大程度上決定了跨平台支持的能力。有的編碼方式是平台無關的,有的則僅限於某種特定的平台。WCF提供了3種典型的編碼方式:Binary、Text和MTOM。Binrary以二進製的方式進行消息的編碼,但是僅限於.NET平台之間的通信;Text則提供平台無關的基於文本的編碼方式。MTOM編碼基於WS-MTOM規範,對於改善大規模二進製數據在SOAP消息的傳輸性能具有重大的意義,既然該編碼方式遵循相應的規範,無疑這也是一種跨平台的編碼方式。

[第20篇] 服務在WCF體係中是如何被描述的?

任何一個程序都需要運行於一個確定的進程中,進程是一個容器,其中包含程序實例運行所需的資源。同理,一個WCF服務的監聽與執行同樣需要通過一個進程來承載。我們將為WCF服務創建或指定一個進程的方式稱為服務寄宿(Service Hosting)。服務寄宿的本質通過某種方式,創建或者指定一個進程用以監聽服務的請求和執行服務操作,為服務提供一個運行環境。

服務寄宿的方式大體分兩種:一種是為一組WCF服務創建一個托管的應用程序,通過手工啟動程序的方式對服務進行寄宿,所有的托管的應用程序均可作為WCF服務的宿主,比如Console應用、Windows Forms應用和ASP.NET應用等,我們把這種方式的服務寄宿方式稱為自我寄宿(Self Hosting)。另一種則是通過操作係統現有的進程激活方式為WCF服務提過宿主,Windows下的進程激活手段包括IIS、Windows Service或者WAS(Windows Process Activation Service)等。

服務寄宿的手段是為一個 WCF服務類型創建一個ServiceHost對象(或者任何繼承於ServiceHostBase的對象)。無論采用哪種寄宿方式,在為某個服務創建 ServiceHost的過程中,WCF框架內部會執行一係列的操作,其中最重要的步驟就是為服務創建服務描述(Service Description)。在本篇文章中,我們將對服務描述進行全麵的介紹。

[第21篇] WCF基本的異常處理模式[上篇][中篇][下篇]

由於WCF采用.NET托管語言(C#和NET)作為其主要的編程語言,注定以了基於WCF的編程方式不可能很複雜。同時,WCF設計的一個目的就是提供基於非業務邏輯的通信實現,為編程人員提供一套簡單易用的應用編程接口(API)。WCF編程模式的簡單性同樣體現在異常處理上麵,本篇文章的主要目的就是對WCF基於異常處理的編程模式做一個簡單的介紹。

[第22篇] 深入剖析WCF底層異常處理框架實現原理[上篇][中篇][下篇]

對於上一篇文章 (WCF基本異常處理模式:[上篇][中篇][下篇]),主要是站在最終開發者的角度對WCF關於異常處理編程模式進行了介紹,接下來,我們需要將我們的目光轉移到WCF框架內部,深入剖析整個WCF異常處理流程。

[第23篇] 服務實例(Service Instance)生命周期如何控製[上篇][中篇][下篇]

服務調用的目的體現在對某項服務功能的消費上,而功能的實現又定義在相應的服務類型中。不論WCF服務端框架處理服務調用請求的流程有多麼複雜,最終都落實在服務實例的激活和操作方法的執行上麵。WCF中的實例管理(Instance Management)旨在解決服務實例的激活和服務實例生命周期的控製。

會話(Session)的目的在於保持來自相同客戶端(服務代理)多次服務調用之間的狀態。從消息交換的角度來講,會話通過消息識別機製判斷調用某個服務的消息來源,從而將來自相同客戶端的所有消息關聯在一起。所以,會話實現了消息關聯(Message Correlation)。

實例與會話是WCF非常重要的兩個特性,它們既相對獨立,又互相製約。實例模式與對會話支持程度的不同組合,會讓最終的服務表現出截然不同的行為。對實例管理和會話的合理利用,對於改善和提高WCF服務應用的可擴展性(Scalability)、性能(Performance)、吞吐量(Throughput)等具有決定性作用。

[第24篇] ServiceDebugBehavior服務行為是如何實現異常的傳播的?

服務端隻有拋出FaultException異常才能被正常地序列化成Fault消息,並實現向客戶端傳播。對於一般的異常(比如執行Divide操作拋出的DivideByZeroException),在默認的情況下,異常信息無法實現向客戶端傳遞。但是,倘若為某個服務應用了ServiceDebugBehavior這麼一個服務行為,並開啟了IncludeExceptionDetailInFaults開關,異常信息將會原封不動地傳播到客戶端。WCF內部是如何處理拋出的非FaultException異常的呢?

[第25篇] 元數據(Metadata)架構體係全景展現[WS標準篇][數據描述篇]

在《WCF技術剖析(卷1)》中,我多次向讀者強調WCF進行通信的本質:終結點是客戶端和服務端進行通信的手段。服務的提供者通過一個或者多個終結點將服務發布出來;服務的消費者則通過創建於之匹配的終結點進行服務的調用。站在服務消費者的角度,這樣一個“匹配”的終結點該如何創建呢?或者說客戶端基於何種信息創建能夠有效調用目標服務的終結點呢?這就是元數據需要解決的問題。

[第26篇] 如何導出WCF服務的元數據(Metadata)[實現篇][擴展篇]

元數據的導出就是實現從ServiceEndpoint對象向MetadataSet對象轉換的過程,在WCF元數據框架體係中,元數據的導出工作由 MetadataExporter實現。MetadataExporter是一個抽象類型,定義了導出元數據的基本行為。WCF定義一個具體的 MetadataExporter:WsdlExporter,將基於某個終結點的元數據導出生成基於WSDL的MetadataSet。我們先來認識 MetadataExporter和MetadataSet。 

WSDL的Binding元素來源於終結點的綁定對象,那麼這些基於Binding的元數據以及相應的策略斷言是如何被寫入WSDL的呢?WSDL導出擴展(WSDL Export Extension)和策略導出擴展(Policy Export Extension)就是為此設計的。

[第27篇] 如何將一個服務發布成WSDL[編程篇][基於WS-MEX的實現][基於HTTP-GET的實現]

對於WCF服務端元數據架構體係來說,通過MetadataExporter將服務的終結點導出成MetadataSet,僅僅是完成了一半的工作。被成功導出的以MetadataSet對象表示的元數據需要最終作為可被訪問的網絡資源發布出來,才能被服務消費者獲取,進而有效地幫助他們進行服務調用。元數據的發布最終是通過ServiceMetadataBehavior這樣一個服務行為實現的。

可以通過編程或者配置的方式將ServiceMetadataBehavior這樣一個服務形式應用到相應的服務上麵,從而實現基於HTTP-GET或者WS-MEX的元數據發布機製。那麼在WCF內部具體的實現原理又是怎樣的呢?相信很多人對此都心存好奇,本篇文章為為你揭示其本質。

[第28篇] 自己動手獲取元數據[附源代碼下載]

元數據的發布方式決定了元數據的獲取行為,WCF服務元數據架構體係通過ServiceMetadataBehavior實現了基於WS-MEX和 HTTP-GET的元數據發布,針對這兩種不同的協議,元數據獲取的實現方式也是不同的,本片文章中通過自己的方式進行元數據獲取,可以看成是對WCF客戶端元數據框架的模擬。 

[第29篇] 換種不同的方式調用WCF服務[提供源代碼下載]

我們有兩種典型的WCF調用方式:通過SvcUtil.exe(或者添加Web引用)導入發布的服務元數據生成服務代理相關的代碼和配置;通過ChannelFactory創建服務代理對象。在這篇文章中,我們采用一種獨特的方式進行服務的調用。

[第30篇] 一個很有用的WCF調用編程技巧[上篇][下篇]

在進行基於會話信道的WCF服務調用中,由於受到並發信道數量的限製,我們需要及時的關閉信道;當遇到某些異常,我們需要強行中止(Abort)信道。在真正的企業級開發中,正如我們一般不會讓開發人員手工控製數據庫連接的開啟和關閉一樣,我們一般也不會讓開發人員手工去創建、開啟、中止和關閉信道,這些工作是框架應該完成的操作。這篇文章,我們就來介紹如果通過一些編程技巧,讓開發者能夠無視“信道”的存在,像調用一個普通對象一樣進行服務調用。


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-30 11:04:49

  上一篇:go  《Enterprise Library深入解析與靈活應用》博文係列匯總
  下一篇:go  《WCF的綁定模型》博文係列匯總[共6篇]