閱讀846 返回首頁    go 技術社區[雲棲]


WCF服務端運行時架構體係詳解[中篇]

在這篇文章中,我們對信道分發器本身作一個深入的了解,首先來看看它具有哪些可供擴展的組件,以及我們可以針對信道分發器對WCF實現哪些可能的擴展。

目錄:
ErrorHandler & ServiceThrottle
ChannelInitializer
IncludeExceptionDetailInFaults
ManualAddressing
MaxPendingReceives
ReceiveSynchronously
IsTransactedReceive & MaxTransactedBatchSize
TransactionIsolationLevel & TransactionTimeout

信道分發器對應的類型為ChannelDispatcher,下麵的代碼片斷給出了ChannelDispatcher部分屬性成員的定義。而這些屬性代表了包含在信道分發器中那些。信道分發器是基於信道監聽器創建的,後者用於請求消息的監聽和消息接收信道棧的創建。信道監聽器對應於隻讀屬性。

   1: public class ChannelDispatcher : ChannelDispatcherBase
   2: {
   3:     //其他成員
   4:     public SynchronizedCollection<IChannelInitializer> ChannelInitializers { get; }
   5:     public Collection<IErrorHandler> ErrorHandlers { get; }
   6:     public ServiceThrottle ServiceThrottle { get; set; }
   7:     
   8:     public override IChannelListener Listener { get; }
   9: }

而屬性ErrorHandlers代表的是一組ErrorHandler對象的集合。而ErrorHandler用於異常的處理的錯誤消息的提供。而類型為ServiceThrottle的同名屬性用於進行流量控製,相關的內容你也可以參考《WCF中並發(Concurrency)與限流(Throttling)》。

至於屬性ChannelInitializers,則代表的是一組實現了接口System.ServiceModel.Dispatcher.IChannelInitializer的被稱為信道初始化器的對象。顧名思義,所謂信道初始化器,就是當服務信道被創建之後用於對其進行初始化操作。接口IChannelInitializer的定義如下,它隻具有一個唯一的Initialize方法。

   1: public interface IChannelInitializer
   2: {
   3:     void Initialize(IClientChannel channel);
   4: }

從擴展性角度來講,你可以將自定義的ErrorHandler和ServiceThrottle應用到信道分發器中分別實現對異常的處理和流量的控製。你也可以自定義信道初始化器改變創建的信道狀態。上述的關於信道分發器的結構可以簡單地通過下圖表示。

clip_image002信道分發器結構

為了實現自定義的異常處理和流量擴展等功能,你可以將自定義的相關組件應用到信道分發器中。另一方麵,信道分發器本身具有一些用於控製器運行行為的屬性。你也可以。下麵的代碼片斷列出了信道分發器主要的可供修改的屬性。其中通過屬性MessageVersion表示的消息的版本(SOAP版本和WS-Addressing版本)決定於綁定的同名屬性。

   1: public class ChannelDispatcher : ChannelDispatcherBase
   2: {
   3:     //其他成員
   4:     public bool IncludeExceptionDetailInFaults { get; set; }
   5:     public bool ManualAddressing { get; set; }
   6:     public MessageVersion MessageVersion { get; set; }
   7:     public int MaxPendingReceives { get; set; }
   8:     public bool ReceiveSynchronously { get; set; }
   9:     public bool IsTransactedReceive { get; set; }
  10:     public int MaxTransactedBatchSize { get; set; }
  11:     public IsolationLevel TransactionIsolationLevel { get; set; }
  12:     public TimeSpan TransactionTimeout { get; set; }
  13: }

IncludeExceptionDetailInFaults:表示服務端拋出的異常的詳細信息是否需要通過錯誤消息回傳給客戶端。基於安全的需要,該屬性的默認值為False。通常隻有在調試的時候我們才需要讓客戶端得到服務端原始的錯誤信息,所以這個開關由服務行為ServiceDebugBehavior來控製。如下麵的代碼所示,ServiceDebugBehavior具有一個同名的屬性。你也可以直接通過在服務類型上應用ServiceBehaviorAttribute特性通過命名屬性控製這個開關。關於該屬性背後的原理,你可以參考我的文章《ServiceDebugBehavior服務行為是如何實現異常的傳播的?

   1: public class ServiceDebugBehavior : IServiceBehavior
   2: {
   3:     //其他成員
   4:     public bool IncludeExceptionDetailInFaults { get; set; }
   5: }
   6: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
   7: {    
   8:     //其他成員
   9:     public bool IncludeExceptionDetailInFaults { get; set; }
  10: }

而屬性ManualAddressing則涉及到尋址(Addressing)的概念。對於一個支持WS-Addressing的SOAP消息來說,在其報頭列表中包括一係列WS-Addressing報頭(比如To、ReplyTo、RelatesTo等)以提供消息路由需要的尋址信息。在默認的情況下,這些尋址報頭最終是通過位於信道棧最底層的傳輸信道(Transport Channel)來添加的。但是在某些情況下,我們希望手工地位消息添加相應的尋址報頭,並希望該消息按照這些手工添加的尋址信息進行路由。我們將這種機製成為手工尋址(Manual Addressing)。

如果啟用手工尋址,當消息最終通過傳輸信道向傳輸層發送的時候,傳輸信道會認為相應的尋址報頭已經被成功添加,所以不會進行尋址報頭的重複添加。ChannelDispatcher的ManualAddressing屬性表示是否啟用了手工尋址,其默認值決定於綁定的傳輸綁定元素的同名屬性。按照尋址的需要,你可以在運行時動態變該屬性值強製啟用或者禁用手工尋址。

   1: public abstract class TransportBindingElement : BindingElement
   2: {
   3:     //其他成員
   4:     public bool ManualAddressing { get; set; }
   5: }

MaxPendingReceives表示允許的最大掛起(未處理)的消息數,默認值為1。該值可以通過終結點行為DispatcherSynchronizationBehavior來修改。如下所示,DispatcherSynchronizationBehavior具有一個同名的屬性。

   1: public class DispatcherSynchronizationBehavior : IEndpointBehavior
   2: {
   3:     //其他成員
   4:     public int MaxPendingReceives { get; set; }
   5: }

對於服務端信道層對請求消息的接收,到底采用同步還是異步的方式更加有效往往取決於具體采用的通信方式。在默認的情況下,對於同步/異步消息接收方式的選擇取決於終結點的綁定。對於所有的係統預定義綁定類型,它們都實現了一個特殊的接口IBindingRuntimePreferences。如下麵的代碼片斷所示,IBindingRuntimePreferences接口具有一個唯一的隻讀屬性:ReceiveSynchronously。該屬性就表示具體的綁定是否應該采用同步的消息接收方式。而在默認的情況下,綁定的ReceiveSynchronously屬性值被作為對應的信道分發器的同名屬性值。

   1: public interface IBindingRuntimePreferences
   2: {
   3:     bool ReceiveSynchronously { get; }
   4: }

對於幾個我們常用的係統預定義綁定(BasicHttpBinding、WSHttpBinding、WSHttp2007Binding、WSDualHttpBinding、NetTcpBinding、NetNamedPipeBinding和NetMsmqBinding),除了NetMsmqBinding的ReceiveSynchronously屬性可以是True外,其他綁定的該屬性總是返回False。也就是說,除了NetMsmqBinding,其他的綁定總是以異步的方式進行消息的接收,這樣可以及時地處理同時抵達的消息請求,並極大的改善服務的吞吐量。而對於NetMsmqBinding來說,它的ReceiveSynchronously屬性和ExactlyOnce具有相同的值。

雖然在默認的情況下,綁定的ReceiveSynchronously屬性決定了信道分發器的同名屬性。但是你也可以通過擴展來改變該屬性值。實際上,WCF為我們定義了一個類型為System.ServiceModel.Description.SynchronousReceiveBehavior的終結點行為來對信道分發器的ReceiveSynchronously屬性值進行設定。當終結點應用了該行為之後,對應的信道分發器被自動設置為True,意味著采用同步的方式接收請求消息。

接下來,我們來關於信道分發器與事務相關的幾個屬性。首先是基於事務的消息接收。為了判斷某個綁定是否支持事務性消息接收,WCF定義了名稱為System.ServiceModel.Channels.ITransactedBindingElement的接口。從下麵給出的定義可以看出,ITransactedBindingElement具有唯一的隻讀屬性TransactedReceiveEnabled,表明是否需要將消息的接收工作納入到事務中進行。

   1: public interface ITransactedBindingElement
   2: {
   3:     bool TransactedReceiveEnabled { get; }
   4: }

從接口的名稱我們就可以看出來,ITransactedBindingElement是為綁定元素定義的接口。對於一個具體的綁定來說,隻要它的綁定元素列表中具有任何一個綁定元素實現了ITransactedBindingElement接口,並且TransactedReceiveEnabled屬性返回True,就意味著這是一個基於事務性消息接收的綁定。而綁定的是否支持事務性消息接收在默認的情況下反應在信道分發器的IsTransactedReceive屬性上,而另一個屬性MaxTransactedBatchSize則表示允許納入同一個事務進行的最大消息接收操作數。對於WCF預定義的所有綁定元素,隻有基於MSMQ的兩個綁定元素MsmqTransportBindingElementMsmqIntegrationBindingElement實現了ITransactedBindingElement接口。

對於最初決定於綁定的這兩個基於事務性消息接收的屬性,我們也可以通過擴展對其進行動態修改以強製或者避免進行事務性消息接收。而對於MaxTransactedBatchSize屬性的設定,WCF同樣為我們定義了相應的終結點屬性:System.ServiceModel.Description.TransactedBatchingBehavior。信道分發器的MaxTransactedBatchSize對應於TransactedBatchingBehavior的MaxBatchSize屬性。

   1: public class TransactedBatchingBehavior : IEndpointBehavior
   2: {   
   3:     //其他成員
   4:     public int MaxBatchSize { get; set; }
   5: }

如果你閱讀看了我的文章《WCF事務編程([上篇][中篇][下篇])》你應該對信道分發器的另外兩個基於事務的屬性TransactionIsolationLevel和TransactionTimeout不會感到陌生。它們代表在事務的隔離級別和超時時限。這兩個屬性對應於我們熟悉的ServiceBehaviorAttribute特性的同名屬性。

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //其他成員
   5:     public IsolationLevel TransactionIsolationLevel { get; set; }
   6:     public string TransactionTimeout { get; set; }
   7: }

WCF服務端運行時架構體係詳解[上篇]
WCF服務端運行時架構體係詳解[中篇]
WCF服務端運行時架構體係詳解[下篇]
WCF服務端運行時架構體係詳解[續篇]


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

最後更新:2017-10-26 16:04:50

  上一篇:go  WCF服務端運行時架構體係詳解[上篇]
  下一篇:go  WCF服務端運行時架構體係詳解[下篇]