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, "http://127.0.0.1:3721/orderservice");                
  10:             host.Open();
  11:             Console.Read();
  12:         }
  13:     }
  14: }

 当上面的代码执行到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的产生。

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-07-28 21:43:36

WCF中关于可靠会话的BUG!!的相关文章

使命必达: 深入剖析WCF的可靠会话[编程篇](下)

整个可靠会话的机制是完全在信道层实现的,而整个信道层的最终缔造者就是绑定,所以可靠会话编程是围绕着绑定进行的.<上篇>对实现可靠会话的绑定元素已经如何使用系统绑定实现可靠会话进行了介绍,下篇将和你探讨WCF可靠会话编程模型余下两个主题:自定义绑定和对消息传递的强制约束. 一.为自定义绑定的可靠会话进行设置 绑定是一系列绑定元素的有序组合,但是系统绑定为我们提供适应了某种典型通信环境的绑定元素组合方式,可以看成是"套餐".但是,如果套餐不符合您的胃口,你应该查看菜单点你喜欢的

使命必达: 深入剖析WCF的可靠会话[协议篇](上)

在<实例篇>中,我通过可靠会话实现了对图片的可靠.有序的传输:在<概念篇>中,我们对可靠消息涉及到的可靠消息传输(RM)的相关概念进行了讲述.在WS-*大家庭中,WS-RM为可靠消息传输提供了一个一个规范,使互操作成为可能.在<协议篇>中,我们侧重对WS-RM的介绍. WS-RM,为WS-Reliable Messaging的简称,是WS-*大家庭的一个重要成员.和前面介绍的WS-Coordination和WS-AT一样,WS-RM的制定者是结构化信息标准促进组织(OA

使命必达: 深入剖析WCF的可靠会话[实例篇](内含美女图片,定力差者慎入)

通过前面一系列的博文(<WCF 并发(Concurrency)的本质>.<并发中的同步>.<实践重于理论>.<并发与实例上下文模式>.<回调与并发>.<ConcurrencyMode.Multiple 模式下的WCF服务就一定是并发执行的吗[上篇]>.<ConcurrencyMode.Multiple 模式下的WCF服务就一定是并发执行的吗[下篇]>.<控制并发访问的三道屏障[上篇]>和<控制并发访问的三

使命必达: 深入剖析WCF的可靠会话[原理揭秘篇](上)

本系列先后通过<实例篇>.<概念篇>.<协议篇>和<编程篇>对WCF的可靠会话进行了详细探讨.作为本系列的最后一片,我们将深入到WCF的可靠会话体系的最底层,对实现可靠会话的实现原理进行深入剖析.如果读者仔细阅读本系列博文,相信会使读者对可靠会话的理解提升到一定的高度. 从<编程篇>中,我们不难看出可靠会话的编程仅仅围绕着一个对象,那就是绑定.绑定在整个WCF架构模型具有重要的地位.WCF整个架构模型由两部分构成,即服务模型(Service Mo

使命必达: 深入剖析WCF的可靠会话[共8篇]

作为一个通信基础平台,WCF必须保证通信的可靠性.由于消息交换是WCF采用的通信手段,通信可靠性的保障体现在确保消息的可靠传输.WCF本质上是一个消息处理框架,作为整个消息交换系统的两个终端,即发送端和接收端.换句话说,WCF仅仅负责对消息的发送和接收,一旦消息通过WCF的信道层进入了网络,就脱离了WCF的控制范围.但是,由于网络环境的限制,网络层不能百分之百地确保对消息的有效交付.如何克服中间环节的制约,确保从一端发送的消息能够被有效地交付给另一端,这就是可靠消息传输(Reliable Mes

一起谈.NET技术,使命必达:深入剖析WCF的可靠会话

作为一个通信基础平台,WCF必须保证通信的可靠性.由于消息交换是WCF采用的通信手段,通信可靠性的保障体现在确保消息的可靠传输.WCF本质上是一个消息处理框架,作为整个消息交换系统的两个终端,即发送端和接收端.换句话说,WCF仅仅负责对消息的发送和接收,一旦消息通过WCF的信道层进入了网络,就脱离了WCF的控制范围.但是,由于网络环境的限制,网络层不能百分之百地确保对消息的有效交付.如何克服中间环节的制约,确保从一端发送的消息能够被有效地交付给另一端,这就是可靠消息传输(Reliable Mes

[转自MSDN]可靠会话(Reliable Session)的最佳实践

一.设置 MaxTransferWindowSize Windows Communication Foundation (WCF) 中的可靠会话使用传输窗口保存客户端和服务上的消息.可配置属性 MaxTransferWindowSize 指示传输窗口可以保存多少条消息. 在发送方,这指示在等待确认消息时传输窗口可以保存多少条消息,在接收方,则指示为服务缓冲多少条消息. 选择合适的大小可影响使用网络的效率以及运行服务的最佳容量.以下各节将详细介绍选择此属性的值时要考虑的事宜以及值的影响. 默认传输

使命必达: 深入剖析WCF的可靠会话[原理揭秘篇](下)

上面一部分我们站在信道层的角度剖析了WCF为了实现可靠会话在信道层进行的一系列消息交换,或者说客户端和服务端的RS信道为了实现可靠消息传输所进行一轮又一轮的握手.这一切都是基于这样一个假设:两个RS信道均可以在适当的时机向对方发送消息,或者说两个RS信道之间是一个双工的通道. 如果我们站在传输层看待这个问题,该假设对于TCP传输是成立的,但是对于HTTP来说就有点问题了.HTTP本身就是一个基于请求|回复消息交换模式的应用层网络协议,并不能对双工通信提供支持.而WCF通过WSDualHttpBi

使命必达: 深入剖析WCF的可靠会话[概念篇]

在<实例篇>中,我通过可靠会话成功地进行了美女图片的传输,相信大家在保了眼福之余,会对WCF的可靠会话的功用具有一个深刻的认识.实际上,这涉及到WS中一个重要的概念--可靠消息传输(RM:Reliable Messaging).如果想对可靠会话有一个深入的认识,对可靠消息传输的了解是必须的. 一.可靠消息传输(Reliable Messaging) 我们可以将一个通过WCF构建的分布式应用划分为两个部分,即客户端应用和服务端应用,它们之间的交互方式即采用某种MEP的消息交换.在这里,我们需要通