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: }

 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
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
数据库 C# 数据安全/隐私保护
使用分布式框架WCF出现的BUG记录
使用分布式框架WCF出现的BUG记录
|
前端开发
WCF更新服务引用报错的原因之一
WCF更新服务引用报错的原因之一
|
C# 数据安全/隐私保护
c#如何创建WCF服务到发布(SqlServer版已经验证)
c#如何创建WCF服务到发布(SqlServer版已经验证)
81 0
|
安全 数据库连接 数据库
WCF服务创建到发布(SqlServer版)
在本示例开始之前,让我们先来了解一下什么是wcf? wcf有哪些特点? wcf是一个面向服务编程的综合分层架构。该架构的项层为服务模型层。 使用户用最少的时间和精力建立自己的软件产品和外界通信的模型。它使得开发者能够建立一个跨平台的安全、可信赖、事务性的解决方案。且能与已有系统兼容写作。 简单概括就是:一组数据通信的应用程序开发接口。
123 0
|
C++
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
147 0
WCF基础教程(二)——解析iis8和iis8.5+VS2013发布wcf服务问题
WCF使用纯代码的方式进行服务寄宿
服务寄宿的目的是为了开启一个进程,为WCF服务提供一个运行的环境。通过为服务添加一个或者多个终结点,使之暴露给潜在的服务消费,服务消费者通过匹配的终结点对该服务进行调用,除去上面的两种寄宿方式,还可以以纯代码的方式实现服务的寄宿工作。
897 0
|
Windows
WCF服务寄宿到IIS
一.WCF简介: Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows 通讯开发平台。整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。
1104 0
WCF服务自我寄宿
WCF服务的寄宿方式 WCF寄宿方式是一种非常灵活的操作,可以寄宿在各种进程之中,常见的寄宿有: IIS服务、Windows服务、Winform程序、控制台程序中进行寄宿,从而实现WCF服务的运行,为调用者方便、高效提供服务调用。
1043 0