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


WCF中關於可靠會話的BUG!!

對WCF的可靠會話編程有一定了解的人應該知道,我們可以使用 DeliveryRequirementsAttribute 可以指示WCF確認綁定提供服務或客戶端實現所需的功能。如果在從應用程序配置文件加載服務說明或在代碼中以編程方式生成服務說明時檢測到 DeliveryRequirementsAttribute 屬性,則 WCF 會驗證所配置的綁定,並支持該屬性指定的所有功能。例如,您的服務可能要求綁定支持隊列。使用 DeliveryRequirementsAttribute 可以讓WCF 確認是否滿足下列要求:

但是,當你使用DeliveryRequirementsAttribute 特性的時候,會出現一些很奇怪的現象。經過我個人的分析,這是WCF的一個Bug。

我隨便定義了一個簡單的服務:OrderService。並在服務契約上應用了一個DeliveryRequirementsAttribute 特性,將RequireOrderedDelivery和QueuedDeliveryRequirements分別設置成TRUE和QueuedDeliveryRequirementsMode.Allowed,也就是允許終結點的綁定采用隊列傳遞,但是要求綁定采用有序消息交付。

   1: [Serializable]
   2: public class Order
   3: { }
   4: [ServiceContract]
   5: [DeliveryRequirements(RequireOrderedDelivery = true, QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Allowed )]
   6: public interface IOrderService
   7: {
   8:     [OperationContract]
   9:     void ProcessOrder(Order order);
  10: }
  11: public class OrderService : IOrderService
  12: {
  13:     public void ProcessOrder(Order order)
  14:     {
  15:         throw new NotImplementedException();
  16:     }
  17: }

現在,我通過下麵的代碼對服務進行寄宿,注意終結點綁定的可靠會話特性被開啟,但是Ordered屬性被設置成False。也就是該綁定不滿足通過DeliveryRequirementsAttribute 設置的對有序消息交付的要求

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         using (ServiceHost host = new ServiceHost(typeof(OrderService)))
   6:         {
   7:             WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message, true);
   8:             binding.ReliableSession.Ordered = false;
   9:             host.AddServiceEndpoint(typeof(IOrderService), binding, "https://127.0.0.1:3721/orderservice");                
  10:             host.Open();
  11:             Console.Read();
  12:         }
  13:     }
  14: }

 image當上麵的代碼執行到ServiceHost開啟(host.Open();),會拋出如下的異常。異常信息是“The DeliveryRequirementsAttribute on contract 'IOrderService' specifies a QueuedDeliveryRequirements value of NotAllowed.  However, the configured binding for this contract specifies that it does support queued delivery.  A queued binding may not be used with this contract.”翻譯成中文就是“服務契約'IOrderService' 上的 DeliveryRequirementsAttribute 指定了 NotAllowed 的 QueuedDeliveryRequirements 值。但是,為此協定配置的綁定指定其不支持排隊傳送。排隊綁定可能不能用於此契約”。實際上在這裏QueuedDeliveryRequirements是Allowed,不應該出現如此的錯誤信息。

二、資源的錯誤定義導致異常消息不正確

我們對上麵拋出的異常進行進一步地追蹤,你會現在該異常的StackTrace如下。可以看出來,異常是在執行DeliveryRequirementsAttribute 的EnsureOrderedDeliveryRequirements方法時拋出來的。

at System.ServiceModel.DeliveryRequirementsAttribute.EnsureOrderedDeliveryRequirements(String name, Binding binding)
at System.ServiceModel.DeliveryRequirementsAttribute.ValidateEndpoint(ServiceEndpoint endpoint)
at System.ServiceModel.DeliveryRequirementsAttribute.System.ServiceModel.Description.IContractBehavior.Validate(ContractDescription description, ServiceEndpoint endpoint)
at System.ServiceModel.Description.ServiceEndpoint.Validate(Boolean runOperationValidators, Boolean isForService)
at System.ServiceModel.Description.DispatcherBuilder.ValidateDescription(ServiceDescription description, ServiceHostBase serviceHost)
at System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost)
at System.ServiceModel.ServiceHostBase.InitializeRuntime()
at System.ServiceModel.ServiceHostBase.OnBeginOpen()
at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
at ConsoleApplication4.Program.Main(String[] args) in D:\Users\jinnan\Documents\Visual Studio 2008\Projects\ConsoleApplication4\ConsoleApplication4\Program.cs:line 23
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

實際上,從名稱就可能看出EnsureOrderedDeliveryRequirements方法是在驗證終結點綁定的有序消息交付能,和隊列消息傳遞一點關係都沒有。通過Reflector,我們看看EnsureOrderedDeliveryRequirements方法的實現。

   1: private void EnsureOrderedDeliveryRequirements(string name, Binding binding)
   2: {
   3:     if (this.RequireOrderedDelivery)
   4:     {
   5:         IBindingDeliveryCapabilities property = binding.GetProperty<IBindingDeliveryCapabilities>(new BindingParameterCollection());
   6:         if (property == null)
   7:         {
   8:             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SinceTheBindingForDoesnTSupportIBindingCapabilities1_1", new object[] { name })));
   9:         }
  10:         if (!property.AssuresOrderedDelivery)
  11:         {
  12:             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("TheBindingForDoesnTSupportOrderedDelivery1", new object[] { name })));
  13:         }
  14:     }
  15: }
  16:  
  17:  
  18:  
  19:  

從上麵的邏輯我們可以看到,如果“有序消息交付”驗證失敗會拋出InvalidOperationException異常,這和我們前麵的StackTrace是一致的。而異常消息則定義在資源文件中。該資源文件的Key是“TheBindingForDoesnTSupportOrderedDelivery1”。為此,在此利用Reflector,看看資源項的定義,結果證實資源字符串的內容和上麵拋出的異常消息是吻合的。所以,我們可以說由於WCF資源字符串的錯誤定義或者錯誤使用導致了這個Bug的產生。

image


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

最後更新:2017-10-27 14:34:47

  上一篇:go  又一個中國方案輸出全世界!天貓雙11“五個全球”讓世界小得像街
  下一篇:go  使命必達: 深入剖析WCF的可靠會話[編程篇](下)