可信赖会话

  WCF的可信赖会话在绑定层保证消息只会被传输一次,并且保证消息间的顺序。当使用TCP通信时,协议本身保证了可靠性,但它只在两点间的网络 包这个层面提供了这样的保证。WCF的可信赖会话特性保证了在传输过程中消息不会丢失、重复或错位。这种保证是消息层面的,且适用于任何数目节点间的通 信。另外,使用可信赖会话时,WCF会重连掉线的连接,在重连失败时还会释放会话占用的相关资源。可信赖会话还会通过调整消息的发送频率来缓解网络拥挤。

  为使用WCF的可信赖会话,必须选择支持可信赖会话的绑定。支持这一特性的预定义绑定包括WSHttpBinding、 WSDualHttpBinding、WSFederationBinding、NetTcp-Binding和 NetNamedPipesBinding。在WSHttpBinding、WSDualHttpBinding和 WSFederationBinding的情况下,可信赖特性默认是关闭的,对其他绑定而言,默认是打开的。打开或关闭可信赖会话特性只要按如下方式自定 义绑定即可:

  1.  
  2. <system.serviceModel>
  3. <services>
  4. <service>
  5. <endpoint binding="wsHttpBinding" bindingConfiguration="MyReliableConfiguration"
  6. [...]
  7. />
  8. </service>
  9. </services>
  10. <bindings>
  11. <wsHttpBinding>
  12. <binding name="MyReliableConfiguration">
  13. <reliableSession enabled="true" ordered="true"/>
  14. </binding>
  15. </wsHttpBinding>
  16. </bindings>
  17. </system.serviceModel>

  也可以通过包含System.ServiceModel.Channels.ReliableSessionBindingElement绑定元素为自定制的绑定添加可信赖会话特性。

  1.  
  2. <system.serviceModel>
  3. <services>
  4. <service name="[...]">
  5. <endpoint
  6. [...]
  7. binding="customBinding"
  8. bindingConfiguration="MyReliableCustomBinding">
  9. </endpoint>
  10. </service>
  11. </services>
  12. <bindings>
  13. <customBinding>
  14. <binding name="MyReliableCustomBinding">
  15. <reliableSession ordered="false"/>
  16. <httpTransport />
  17. </binding>
  18. </customBinding>
  19. </bindings>
  20. </system.serviceModel>

  WCF开发者可以指出他们的代码将依赖于对消息传送的保证。比如,他们可以指出将假定消息按照它们发出的顺序传送。

  1. [ServiceContract(SessionMode=SessionMode.Required)]
  2. [DeliveryRequirements(RequireOrderedDelivery=true)]
  3. publicinterface IMyServiceContract

  为服务契约添加这样的定义将导致WCF检查任何包含该服务契约的终结点,以确认它们选择了支持可信赖会话的绑定,并且被正确地配置以保证按顺序传送。

会话管理

  会话管理允许WCF应用程序将其接收到的消息作为会话的一部分来对待,也就是作为与另一个应用程序进行交换的统一序列消息的一部分。

  所以,WCF的应用程序开发者就可以通过如下的方式来编码处理消息:一个消息的处理需要依靠前一个消息的信息。如果需要编写这样的代码,可以将 System.Service-ModelServiceContract特性的SessionMode参数设为 System.ServiceModel.SessionMode.Required值:

  1. [ServiceContract(SessionMode=SessionMode.Required)]
  2. publicinterface IMyServiceContract

  这将让WCF检查为契约中包含的终结点选择的绑定是否支持会话,并将信息合并到消息中以识别会话。支持该功能的预定义绑定包括 WSHttpBinding、WSDualHttp-Binding、WSFederationBinding、NetTcpBinding、 NetNamedPipesBinding和NetMsmqBinding。

  开发者可以在实例上下文会话中存储或检索与会话相关的数据:

  1.  
  2. publicclass MyExtension : IExtension<InstanceContext>
  3. {
  4. publicstring sessionIdentifier =null;
  5. public MyDataType MyData =null;
  6. }
  7.  
  8. publicvoid FirstRequest(MyDataType myData)
  9. {
  10. MyExtension extension =new MyExtension();
  11. extension.sessionIdentifier = OperationContext.SessionId;
  12. extension.MyDataType = myData;
  13. OperationContext.InstanceContext.Extensions.Add(myData);
  14. }
  15.  
  16. public MyDataType SubsequentRequest()
  17. {
  18. Collection<MyExtension> extensions = OperationContext.InstanceContext.
  19. Extensions.FindAll<MyExtension>();
  20. foreach(MyExtension extension in extensions)
  21. {
  22. if(string.Compare(extension.sessionIdentifier, OperationContext.SessionId, true)==)
  23. return extension.MyData;
  24. }
  25. returnnull;
  26. }

  为更好地管理会话的相关资源,开发者可指定哪些操作开始会话,哪些操作结束会话:

  1.  
  2. [ServiceContract(SessionMode=SessionMode.Required)]
  3. publicinterface IMyServiceContract
  4. {
  5. [OperationContract(IsInitiating=true)]
  6. void StartSession();
  7. [OperationContract(IsTerminating=true)]
  8. void StopSession();
  9. }

队列交付

  可信赖会话提供的消息传送保证只能作用在宿主程序域的生命周期里。如果一个消息在传送过程中丢失了,但发送消息的程序域在发现消息丢失前终止了,当程序域重新运行后,它就不知道这个消息已经丢失了。实际上,它将丢掉整个被丢失的消息所在会话的上下文。

  WCF能够通过MSMQ(Microsoft Message Queuing,Microsoft消息队列)发送消息,这为消息传送提供了独立于发送和接收应用程序域的生命周期的保证。队列代表接收应用程序存储发送 应用程序发出的消息。在消息已经存储到队列之后的某个时间,接收应用程序将获得这个消息。

  优先:

  1. 如果接收应用程序因为某些原因(如网络中断等)不能接收消息,发送应用程序仍可以发送消息然后继续做其他事件。消息将一直放在队列里,直到接收应用程序可以接收这些消息为止。

  2. 发送和接收应用程序间的网络带宽并不是一致的,使用MSMQ的主要限制是MSMQ只能存储小于4MB的消息。

  3. 接收应用程序不应该被不可预测的大量请求压垮。应用程序可以从队列里以它希望的速度获取消息。

  4. MSMQ是一项大多数系统管理员都熟悉的技术,操作系统也提供了Microsoft Management Console管理单元来管理MSMQ。

  队列可以用在两个WCF应用程序间的通信,也可以用于WCF应用程序与一个使用MSMQ的非WCF应用的通信。

  为使用MSMQ队列从一个WCF应用程序发送消息到另一个WCF应用程序,可以使用预定义的NetMsmqBinding。

  1.  
  2. <services>
  3. <service name="Fabrikam.TradeRecorder">
  4. <host>
  5. <baseAddresses>
  6. <add baseAddress="net.msmq://localhost/private/"/>
  7. </baseAddresses>
  8. </host>
  9. <endpoint address="EndpointAddress" binding="netMsmqBinding" [...] />
  10. </service>
  11. </services>

  使用预定义NetMsmqBinding绑定的终结点,必须在地址里使用net.msmq策略。地址的下一段指定了队列所在的主机。如果队列是私有的,那么private段是必需的。最后一段是终结点自身的地址,它必须是指定主机上的事务性MSMQ队列的名称。

  被配置成通过MSMQ队列接收消息的服务必须和队列本身部署在同一台机器上。这个限制是由于MSMQ只允许对非事务队列进行远程读取,而WCF只能使用NetMsmq-Binding绑定从事务队列接收消息。

  可以配置一个服务的多个实例从同一个队列接收消息。在这种情况下,最空闲的应用程序将接收到下一个消息。

  当一个终结点被配置为从队列获取消息的预定义绑定,WCF将确认终结点契约的所有操作都显式地声明为单向(one-way)。

  1.  
  2. publicinterface IMyServiceContract
  3. {
  4. [OperationContract(IsOneWay=true)]
  5. void FirstOperation(string input);
  6. [OperationContract(IsOneWay=true)]
  7. void SecondOperation(string input);
  8. }

  WCF应用程序的开发者可以为服务契约添加一个特性以指定应用程序将通过队列接收消息。

  1. [ServiceContract(SessionMode=SessionMode.Required)]
  2. [DeliveryRequirements(QueueDeliveryRequirements=QueueDeliveryRequirementsMode.Required]
  3. publicinterface IMyServiceContract

  如果开发者这样做,WCF将确认包含这些服务契约的任何终结点的绑定都是通过队列将消息传送给服务的绑定。

Windows Vista的改进

  Windows Vista和其之后的操作系统对MSMQ进行了一些改进,这些改进与dead-letter和有毒队列(poison queue)有关。

dead-letter队列

  MSMQ消息可以配置要到达的目的队列和从目的队列接收的时间。当这些时间中任何一个过期时,消息将会放到一个被称作dead-letter队 列的系统消息队列中。另外,如果消息被发往事务队列,而发送端的队列管理器没有接收到消息已经从目的队列中读取的肯定确认时,这个消息将被转移到一个事务 dead-letter队列。在Windows Vista和其后的操作系统里,可以创建一个队列并将其指定为另一个队列的dead-letter队列。WCF提供了这项改进的支持,开发者可以为使用队 列发送和接收消息的应用程序指定另一个队列作为dead-letter队列。

  1.  
  2. <client>
  3. <endpoint address="net.msmq://localhost/private$/EndpointAddress"
  4. binding="netMsmqBinding" bindingConfiguration="QueueBinding"
  5. [...] />
  6. </client>
  7. <bindings>
  8. <netMsmqBinding>
  9. <binding name="QueueBinding" deadLetterQueue="Custom"
  10. customDeadLetterQueue="net.msmq://localhost/private$/myDeadLetterQueue">
  11. </binding>
  12. </netMsmqBinding>
  13. </bindings>

有毒队列

  有毒消息是事务队列中不能被接收应用程序处理的消息。当消息从队列中读取而接收应用程序不能处理它时,应用程序会回滚读取这个消息的事务,这个消息也将会被放回到队列中。应用程序再一次读取这个消息,读取和回滚该有毒消息的过程就会无限循环下去。

  在Windows Vista之前,MSMQ本身并没有提供检测或复制有毒消息的功能。WCF为此提供了帮助机制,开发者可以为ReceiveRetryCount和ReceiveErrorHanding属性指定合适的值。

  1.  
  2. <services>
  3. <service name="Fabrikam.TradeRecorder">
  4. <host>
  5. <baseAddress>
  6. <add baseAddress="net.msmq://localhost/private/"/>
  7. </baseAddress>
  8. </host>
  9. <endpoint address="EndpointAddress" binding="netMsmqBinding"
  10. bindingConfiguration="QueueBinding"
  11. [...] />
  12. </service>
  13. </services>
  14. <bindings>
  15. <netMsmqBinding>
  16. <binding name="QueueBinding" receiveRetryCount="0" receiveErrorHandling="Fault">
  17. </binding>
  18. </netMsmqBinding>
  19. </bindings>

  ReceiveRetryCount属性的值定义了什么样的消息是有毒消息--就是那些回滚到队列的次数超过 ReceiveRetryCount属性值的消息。ReceiveErrorHanding属性的值指定了对有毒消息的操作。它的值的选择包含将服务改成 出错状态从而不能继续接收任何消息,或者忽略这个有毒消息消息等。

  Windows Vista和之后的操作系统为此提供了更多的选项。把ReceiveErrorHandling的值设为Move会将有毒消息返回到其发送源。这种情况 下,消息最后会被放入发送源的dead-letter队列里。还有一个选项,把ReceiveErrorHandling的值设为Reject,有毒消息 将会被移到接收队列的一个有毒子队列中。对于一个地址为net.msmq://local-host/privateEndpointAddress的队 列而言,其有毒子队列的地址为net.msmq://localhost/private/EndpointAddress:Poison。

事务

  WCF在预定义绑定中实现了标准的WSAtomicTransaction(WS-AT)协议和Microsoft专有的OleTx协议,这些协议可以用来在消息中加入事务状态的信息。WCF的开发者可以指定将一个操作的代码放在一个事务范围里执行。

  1.  
  2. [ServiceContract]
  3. publicinterface IMyServiceContract
  4. {
  5. [OperationContract(IsOneWay=false)]
  6. [TransactionFlow(TransactionFlowOption.Required)]
  7. void MyMethod();
  8. }
  9.  
  10. publicclass MyServiceType : IMyServiceContract
  11. {
  12. [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
  13. vod MyMethod()
  14. {
  15. [...]
  16. }
  17. }

  任何被指定的必须在一个事务范围里执行的操作都不能被标记为单向方法,因为在操作结束时,有关事务状态的信息必须传回给调用者。TransactionAutoComplete特性指出没有异常发生时,WCF应该自动为操作提交事务。

  如果开发者决定由操作自己来提交事务,可使用WCF的静态System.ServiceModel.OperationContext对象:

  1.  
  2. publicclass MyServiceType
  3. {
  4. [OperationBehavior(TransactionScopeRequired=true, TaansactionAutoComplete=false)]
  5. void MyMethod()
  6. {
  7. //Work gets done here
  8. OperationContext.Current.SetTransactionComplete();
  9. }
  10. }

  如果开发者指定服务的一个操作必须在一个事务的上下文中执行,那么WCF将确认服务配置了一个支持在消息里发送有关事务状态的绑定。提供了该支 持的预定义绑定包括:WSHttpBinding、WSDualHttpBinding、WSFederationBinding、 NetTcpBinding和NetNamedPipesBinding。最后两个绑定允许选择WS-AT协议或OleTx协议,而其他绑定都只使用标准 的WS-AT协议。

  1.  
  2. <bindings>
  3. <netTcpBinding>
  4. <binding name="..." transactionFlow="true" transactionProtocol="OleTransactions"/>
  5. </netTcpBinding>
  6. <wsHttpBinding>
  7. <binding name="..." transactionFlow="true"/>
  8. </wsHttpBinding>
  9. </bindings>

  WCF的客户端开发者可以使用System.Transaction命名空间提供的语法将服务的操作放进一个事务的范围内。

  1.  
  2. ServiceClient client =new ServiceClient("MyServiceEndpointConfiguration");
  3. using(TransactionScope scope =new TransactionScope(TransactionScopeOption.RequiresNew))
  4. {
  5. client.DoSomething([...]);
  6. scope.Complete();
  7. }
  8. client.Close();

  如果服务的操作支持事务,且配置了支持传送有关事务状态的绑定,那么客户端的事务直到服务操作决定提交时才会提交。相反,如果客户端决定不提交事务,服务在客户端事务范围里对事务资源所做的任何操作都将被回滚。

  但这样的设计并不太好,当远程客户端决定将采取何种动作的同时,服务的操作和其资源都会被一直占用。作为一个通用的原则,应该尽量避免使事务超出可信赖范围。

  下图显示了一种更加巧妙地使用WCF实现分布式事务的方法。该方法融合了WCF对会话管理、队列交付和事务消息的支持。

  图中的服务被配置成通过队列从客户端接收消息。客户端首先依次开始一个事务和会话,然后发送一组消息到服务。客户端完成会话,当且仅当客户端提 交该事务时,它发送的消息才会到达队列中。客户端发送的这些单独消息在队列里将会表示成单一条目。在服务端,WCF在队列中检测到这条消息后,会依次开始 一个事务和会话。然后它将单一消息重新分拆成客户端发送的一组单个消息,并将它们一一发送给服务。如果一切顺利,服务会关闭会话然后提交事务。如果在处理 任何消息的过程中出现任何差错,事务将会取消,也就是说,这种情况下,对事务资源中的任何消息,所做的任何处理都会被回滚。这组消息将被转移到有毒消息队 列中,对失败操作需要采取补救措施的服务可以从中读取消息。

  这个设计的优点是,在客户端和服务端的操作不会被对方或它们之间的连接延迟所挂起。客户端和服务端的事务都是独立提交的。客户端的事务保证客户 端保持一致性状态,而服务端的事务保证服务一直处于一致性状态。如果客户端在它的事务范围内失败,服务端不会受影响,因为客户端所发送的消息作为事务的一 部分,不会被传送到服务端的队列中。如果服务端在处理客户发送的消息时失败,尽管客户端和服务端都处于一致性状态,但客户端和服务端的状态并没有相互一 致。在这种情况下,就需要采取一些措施来弥补这种不一致性状态

WCF揭秘学习笔记(4):可信赖会话、会话管理、队列、事务的更多相关文章

  1. WCF揭秘学习笔记(1):基础知识

    最近找工作,面试时经常被问懂不懂WCF.不少招聘高级.NET工程师的要求上都 写着有WCF开发经验的优先考虑.我对于WCF仅仅是通过看一些教学视频这种山寨学习法了解一些.现在要下决心好好学习一下WCF ...

  2. WCF揭秘学习笔记(5):WF定制活动

    WF(Windows Workflow Foundation,Windows工作流基础)为.NET提供了一种基于模型的.声明方式的过程执行引擎,它改变了传统的通过一行行编写代码来开发服务功能的方式. ...

  3. WCF揭秘学习笔记(3):使用DataContractSerializer

    使用DataContractSerializer 终结点(包括地址.绑定.契约)可通过代码以编程方式添加到服务中.如: using(ServiceHost host =new ServiceHost( ...

  4. WCF揭秘学习笔记(2):数据表示

    背景知识 WCF提供了一种语言为软件通信建模,称作服务模型.使用更底层的编程架构提供的类可以从这种语言建立的模型中生成可用的通信软件. 在服务模型使用的语言中,负责通信的软件部分称为服务(servic ...

  5. Spring MVC 学习笔记10 —— 实现简单的用户管理(4.3)用户登录显示全局异常信息

    </pre>Spring MVC 学习笔记10 -- 实现简单的用户管理(4.3)用户登录--显示全局异常信息<p></p><p></p>& ...

  6. Spring MVC 学习笔记9 —— 实现简单的用户管理(4)用户登录显示局部异常信息

    Spring MVC 学习笔记9 -- 实现简单的用户管理(4.2)用户登录--显示局部异常信息 第二部分:显示局部异常信息,而不是500错误页 1. 写一个方法,把UserException传进来. ...

  7. Spring MVC 学习笔记8 —— 实现简单的用户管理(4)用户登录

    Spring MVC 学习笔记8 -- 实现简单的用户管理(4)用户登录 增删改查,login 1. login.jsp,写在外面,及跟WEB-INF同一级目录,如:ls Webcontent; &g ...

  8. GIT学习笔记(3):分支管理

    GIT学习笔记(3):分支管理 何谓分支 GIT是如何存储数据的 GIT不是存储文件差异或者变化量,而是一系列文件的快照.在Git提交时,会保存一个提交(commit)对象,该对象包含一个指向暂存内容 ...

  9. kvm虚拟化学习笔记(四)之kvm虚拟机日常管理与配置

    KVM虚拟化学习笔记系列文章列表----------------------------------------kvm虚拟化学习笔记(一)之kvm虚拟化环境安装http://koumm.blog.51 ...

随机推荐

  1. hadoop mysql install (5)

    reference : http://dblab.xmu.edu.cn/blog/install-mysql/ http://wiki.ubuntu.org.cn/MySQL #install mys ...

  2. Maven 入门篇(下)

    第一篇文章大概的介绍了一下Apache Maven以及它的下载和安装,并且运行了一个简单的示例.那么在对maven有了一点接触后,接下去的一步是要了解maven的核心概念,这样才能在使用maven的时 ...

  3. C++11标准的智能指针、野指针、内存泄露的理解(日后还会补充,先浅谈自己的理解)

    1.野指针的概念.成因以及避免 首先,来说说什么是野指针,所谓野指针就是一个指向未申请访问受限的内存区域或者已经删除了的对象的指针. 什么意思呢?就是本来一个指针指向一个对象.一块内存,但是由于程序( ...

  4. linux驱动程序:控制发光二极管

      一个完整的Linux驱动包括内部处理和交互两部分.其中内部处理主要是指Linux驱动的装载.卸载.与设备文件的相关动作处理以及业务逻辑等.与硬件交互主要是指通过iowrite32.ioread32 ...

  5. DevExpress v18.1新版亮点——ASP.NET Bootstrap篇(二)

    用户界面套包DevExpress v18.1日前终于正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress ASP.NET Bootstrap v18.1 的新功能,快 ...

  6. 使用MyEclipse开发Java EE应用:企业级应用程序项目(上)

    你开学,我放价!MyEclipse线上狂欢继续!火热开启中>> [MyEclipse最新版下载] 一.EAR项目模型 MyEclipse提供企业应用程序项目模型,即EAR项目模型,以及用于 ...

  7. Tomcat学习之二:tomcat安装、配置及目录文件说明

    我们看到tomcat目录/bin文件夹里有个tomcat6w.exe,顾名思义就是tomcat以window方式显示控制台.第1次点击打开它时候,可能会提示:tomcat指定的服务未安装,此时我们可以 ...

  8. python3.6 ubuntu

    apt-get install python3.6-dev 安装 pip install mysqlclient 必备

  9. Jmeter系列培训(1)--开山篇

    ​       一直以来,我们不断分享,有的人喜欢,也有的人不喜欢,这都没什么,喜欢的点个赞,留个言,不喜欢的就不看好了,今天我们继续,关于jmeter我们分享了很多工作遇到的问题的解决方案,但是很多 ...

  10. Codeforces Round #252 (Div. 2) D

    http://codeforces.com/problemset/problem/441/D 置换群的基本问题,一个轮换内交换成正常顺序需要k-1次,k为轮换内元素个数 两个轮换之间交换元素,可以把两 ...