整个可靠会话的机制是完全在信道层实现的而整个信道层的最终缔造者就是绑定所以可靠会话编程是围绕着绑定进行的《上篇》对实现可靠会话的绑定元素已经如何使用系统绑定实现可靠会话进行了介绍下篇将和你探讨WCF可靠会话编程模型余下两个主题自定义绑定和对消息传递的强制约束一为自定义绑定的可靠会话进行设置 绑定是一系列绑定元素的有序组合但是系统绑定为我们提供适应了某种典型通信环境的绑定元素组合方式可以看成是套餐但是如果套餐不符合您的胃口你应该查看菜单点你喜欢的菜肴自定义绑定给了你最大的自由度是能能够根据具体的通信环境自由组合需要的绑定元素 关于可靠会话如果你采用系统绑定你定制的范围其实很窄(仅限于InactivityTimeout和Ordered属性)但是如果你采用自定义绑定由于你操作的对象就是ReliableSessionBindingElement绑定元素所有你可以对所有的选项进行自由配置虽然我们可以通过编程的方式之间将创建的ReliableSessionBindingElement对象添加到绑定的绑定元素集合中但是我们还是强烈建议你通过配置的方式来对可靠会话的相关选项进行定制为了让读者能够了解某个特性的配置我个人觉得最好的办法就是直接让读者看看相关配置节的定义WCF将ReliableSessionBindingElement的配置定义在如下所示的ReliableSessionElement类型中通过ReliableSessionElement你不但可以了解可靠会话相关的配置属性还可以了解到其他相关的配置信息比如最大值最小值和默认值等你可以验证一下它们是否和我们前面的介绍一致 : public sealed class ReliableSessionElement : BindingElementExtensionElement : { : [ConfigurationProperty(acknowledgementInterval DefaultValue=::) TypeConverter(typeof(TimeSpanOrInfiniteConverter)) ServiceModelTimeSpanValidator(MinValueString=::)] : public TimeSpan AcknowledgementInterval { get; set; } : public override Type BindingElementType { get; } : [ConfigurationProperty(flowControlEnabled DefaultValue=true)] : public bool FlowControlEnabled { get; set; } : [ServiceModelTimeSpanValidator(MinValueString=::) TypeConverter(typeof(TimeSpanOrInfiniteConverter)) ConfigurationProperty(inactivityTimeout DefaultValue=::)] : public TimeSpan InactivityTimeout { get; set; } : [IntegerValidator(MinValue= MaxValue=x) ConfigurationProperty(maxPendingChannels DefaultValue=)] : public int MaxPendingChannels { get; set; } : [IntegerValidator(MinValue=) ConfigurationProperty(maxRetryCount DefaultValue=)] : public int MaxRetryCount { get; set; } : [ConfigurationProperty(maxTransferWindowSize DefaultValue=) IntegerValidator(MinValue= MaxValue=x)] : public int MaxTransferWindowSize { get; set; } : [ConfigurationProperty(ordered DefaultValue=true)] : public bool Ordered { get; set; } : protected override ConfigurationPropertyCollection Properties { get; } : [TypeConverter(typeof(ReliableMessagingVersionConverter)) ConfigurationProperty(reliableMessagingVersion DefaultValue=WSReliableMessagingFebruary)] : public ReliableMessagingVersion ReliableMessagingVersion { get; set; } : } 在对自定义绑定进行配置的时候我们只需要在绑定元素集合中添加ReliableSessionElement配置元素并对相应的配置属性进行设置即可下面的XML是服务端的WCF配置我们采用自定义绑定作为终结点绑定该自定义绑定由三个绑定元素组成通过TextMessageEncodingElement对消息进行基于文本编码通过TransportBindingElement采用协议进行传输在两者之间的ReliableSessionBindingElement实现了对消息的可靠传输在bindings/binding/reliableSession配置节中我对所有的属性进行的显式设置 : <?xml version= encoding=utf ?> : <configuration> : <systemserviceModel> : <bindings> : <customBinding> : <binding name=reliableSessionBinding> : <textMessageEncoding /> : <reliableSession acknowledgementInterval=:: flowControlEnabled=false inactivityTimeout=:: maxPendingChannels= maxRetryCount= maxTransferWindowSize= reliableMessagingVersion=WSReliableMessaging /> : <Transport /> : </binding> : </customBinding> : </bindings> : <services> : <service name=ArtechMessageInspectionReceiverCalculatorService> : <endpoint address=:///calculatorservice : binding=customBinding bindingConfiguration=reliableSessionBinding : contract=ArtechMessageInspectionReceiverICalculator /> : </service> : </services> : </systemserviceModel> : </configuration> 看到这里我想有的读者会问这么一个问题一个绑定可以有一系列绑定元素构成那么ReliableSessionBindingElement应该置于何处呢?要搞清楚这个问题需要对WCF的绑定模型有一个大致的了解绑定的目的创建一个用于处理和传输消息的信道栈信道在信道栈的顺序决定于对应的绑定元素的排列顺序可靠会话将客户端和服务端通过ReliableSessionBindingElement创建的可靠信道作为分界线并在它们之间提供消息可靠传输保障也就是说信道栈中位于可靠信道之下(靠近传输信道)部分存在于可靠会话的势力范围之中而上面部分则脱离可靠会话的管辖范围这也是在前面给出的实例中为何我们将用于模拟不可靠网络的绑定元素配置到ReliableSessionBindingElement之下的原因所在 由于在实际的应用中我们主要通过可靠会话为网络传输的不稳定性提供可靠传输的保障所以我们一般将ReliableSessionBindingElement配置到传输绑定元素之上至于消息编码绑定元素是置于ReliableSessionBindingElement之上或者之下均没有关系如果你认真阅读过《WCF技术剖析(卷)》第章你会知道消息编码绑定元素并不参与信道的创建而是将编码的方式传入绑定上下文传输信道据此采用相应的编码方式进行消息的编码或者解码此外为了保证可靠会话的安全性我们需要将可靠会话绑定到一个通过安全会话信道提供的安全上下文中在这种情况下ReliableSessionBindingElement需要位于安全绑定元素之上 我们说WCF可靠会话编程完全就是围绕着绑定进行的可以说得更加具体点是围绕着ReliableSessionBindingElement进行的除了对系统绑定或者自定义绑定进行设置关于可靠会话编程模型还涉及到一个契约行为DeliveryRequirementsAttribute我们可以利用DeliveryRequirementsAttribute对服务契约进行一些基于可靠会话的强制性约束 二通过DeliveryRequirementsAttribute对可靠会话进行强制约束 DeliveryRequirementsAttribute这个自定义特性实际上是一个契约行为我们可以将其应用到服务契约类型或者服务类型上强制要求相应终结点绑定必须满足设定的关于消息传输方面的要求DeliveryRequirementsAttribute定义如下其中忽略了实现IContractBehavior接口的个方法 : [AttributeUsage(AttributeTargetsInterface | AttributeTargetsClass AllowMultiple=true)] : public sealed class DeliveryRequirementsAttribute : Attribute IContractBehavior IContractBehaviorAttribute : { : //其他成员 : public QueuedDeliveryRequirementsMode QueuedDeliveryRequirements { get; set; } : public bool RequireOrderedDelivery { get; set; } : public Type TargetContract { get; set; } : } DeliveryRequirementsAttribute定义了两个属性QueuedDeliveryRequirements和RequireOrderedDelivery分别代表相应的终结点绑定必须满足的两个要求队列传递和有序交付队列传递及采用消息队列(即MSMQ)的机制进行消息传递在下一个系列中我们会对队列服务进行单独介绍而有序交付就是本章涉及的可靠消息传输的有序交付IContractBehavior属性是对IContractBehaviorAttribute的实现当我们将DeliveryRequirementsAttribute特性应用到某个实现了多个服务契约的服务上时可以指定设置的消息传递要求是针对某个服务契约 在服务端当基于服务类型创建的ServiceHost对象被开启的时候如果相应终结点绑定无法满足通过将DeliveryRequirementsAttribute特性应用到服务契约类型或者服务类型上设置的关于队列传输或者有序交付的要求时会抛出一个InvalidOperationException异常如果将DeliveryRequirementsAttribute特性应用到服务契约上客户端在试图开启ChannelFactory<TChannel>对象的时候同样会验证用于服务调用的终结点绑定是否满足相应的要求如果无法满足同样会抛出一个InvalidOperationException异常 举个例子假设我们定义如下一个IOrderService的服务契约用于处理订单在IOrderService接口上应用了DeliveryRequirementsAttribute特性并将RequireOrderedDelivery设置成True要求终结点绑定强制开启可靠消息的有序交付特性 : [ServiceContract(Namespace = ://)] : [DeliveryRequirements(RequireOrderedDelivery = true)] : public interface IOrderService : { : [OperationContract] : void Process(Order order); : } 现在我们对实现该服务契约的服务进行寄宿相应的配置如下从中我们可以看到我们采用WSBinding作为终结点的绑定通过绑定配置开启了可靠会话但是将ordered属性配置成False : ?xml version= encoding=utf ?> : <configuration> : <systemserviceModel> : <bindings> : <wsBinding> : <binding name=reliableSessionBinding> : <reliableSession ordered=false enabled=true /> : </binding> : </wsBinding> : </bindings> : <services> : <service name=ArtechMessageInspectionReceiverOrderService> : <endpoint address=://:/OrderService binding=wsBinding : bindingConfiguration=reliableSessionBinding contract=ArtechMessageInspectionReceiverIOrderService /> : </service> : </services> : </systemserviceModel> : </configuration> 当进行服务寄宿的时候你会得到如图所示的InvalidOperationException异常当你进一步看清具体的异常消息的时候你可能第一感觉就是作者把图片弄错了因为终结点绑定部满足DeliveryRequirementsAttribute设定的关于有序交付的要求和队列传递根据就不相关但是图就是真实运行后的截图这是WCF自身的一个Bug在《WCF 中关于可靠会话的BUG!!》这篇文章中有对该Bug的原因的深入探讨 图 终结点绑定不能满足DeliveryRequirementsAttribute设定的要求导致的异常 到此为止关于WCF可靠会话编程方面的内容就到此为止下一篇我们对可靠会话架构体系进行进一步的挖掘对可靠会话具体的实现原理进行深入剖析敬请期待 |