WCF揭秘—可靠性会话功能
作者:作者不详  发布日期:2012/03/01 17:22:35
  WCF揭秘—可靠性会话功能


一、可靠性会话


Windows Communication Foundation (WCF) 可靠性会话是一个如 WS-ReliableMessaging 协议所定义的 SOAP 可靠消息传递的实现。它在绑定层保证消息只会被传送一次,并能确定消息之间的传输顺序。它的特性在于保证了传输过程中消息不会丢失或者错位,在连接掉线的时候,它会重新连接服务器,连接次数可在配置文件中设定,当在连接失败的时候,能自动释放对话所占用的资源。


系统有多个绑定支持可靠性会话功能:wsHttpBinding、wsDualHttpBinding、wsFederationBinding、netTcpBinding、netNamedPipesBinding。其中wsHttpBinding、wsFederationBinding、netTcpBinding在默认情况下可靠性会话功能是关闭。而wsDualHttpBinding、netNamedPipesBinding则默认支持可靠性功能。


二、开发实例


可靠性会话功能可以通过代码绑定,也可以通过config配置统一绑定,值得注意的是服务器端要与客户端的配置必须保持一致,避免出现冲突。下面以netTcpBinding契约为例子,说明一下可靠性会话的功能。首先建立数据契约Person,和服务契约PersonService,客户端通过GetPerson方法获取Person对象。


服务器端


C# Code:

namespace Pro.Model
{
   //建立数据契约
   [DataContract]
   public class Person
   {
      [DataMember]
      public int ID
      {
         get;
         set;
      }
      
      [DataMember]
      public string Name
      {
         get;
         set;
      }
      
      [DataMember]
      public int Age
      {
         get;
         set;
      }
   }
}

namespace Pro.Service
{
   // 建立服务契约接口“IPersonService”。
   [ServiceContract]
   public interface IPersonService
   {
      [OperationContract]
      Person GetPerson();
   }
   
   // 实现服务契约“PersonService”。
   [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
   public class PersonService : IPersonService
   {
      public Person GetPerson()
      {
         Person person = new Person();
         person.ID = 0;
         person.Name = "Leslie";
         person.Age = 31;
         
         return person;
      }
   }
   
   class Program
   {
      //启动服务
      static void Main(string[] args)
      {
         Console.WriteLine("Service star!");
         ServiceHost host1 = new ServiceHost(typeof(PersonService));
         host1.Open();
         Console.ReadKey();
         host1.Close();
      }
   }
}



添加config配置文件,加入 reliableSession 配置,包含以下属性


1.enable


返回值为bool类型,代表是否打开可靠性功能。


2.inactivityTimeout


返回值为TimeSpan类型,代表闲置超时时间,默认值为10分钟,如果客户端已经建立起服务对象,在超过此时间内没有重新调用这些对象,系统将发送提示信息: “通信对象 System.ServiceModel.Channels.ServiceChannel 无法用于通信,因为其处于‘出错’状态。”。


3.ordered


返回值为bool类型,代表是否开启“有序性”性功能,如果开启此功能,代表消息将按顺序传送。


4.maxPendingChannels


返回值为int 类型,代表最大等候信道,默认值为4。


5.maxRetryCount


返回值为int 类型,表示最大重复发送次数,默认值为8,最大值为20。如果因断线等原因连接失败,客户端重试次数超过此最大值,系统将发出错误提示。


6.flowControlEnabled


返回值为bool类型,默认值为true,代表是否启动流量控制器。启动后,当接收方的传输数据缓冲区已满时,发送方将延迟发送信息。


7.acknowledgementInterval


返回值为TimeSpan类型,默认值为00:00:00.2(即0.2秒),代表接收方在接收信息之前所需要的等待时间。


8.maxTransferWindowSize


返回值为int类型,默认值为8,用于控制数据缓冲区数量。

<configuration>
   <system.serviceModel>
     <behaviors>
       <serviceBehaviors>
         <behavior name="">
           <serviceMetadata httpGetEnabled="false" />
           <serviceDebug includeExceptionDetailInFaults="true" />
         </behavior>
       </serviceBehaviors>
     </behaviors>
 
     <bindings>
       <netTcpBinding>
         <binding name="defaultNetTcpBinding">
           <!--打开可靠性会话功能,把过期时间配置为10秒-->
           <reliableSession enabled="true" inactivityTimeout="00:00:10"/>
         </binding>
       </netTcpBinding>
     </bindings>
 
     <services>
       <service name="Pro.Service.PersonService">
         <!--绑定defaultNetTcpBinding-->
         <endpoint address=""  bindingConfiguration="defaultNetTcpBinding" binding="netTcpBinding" contract="Pro.Service.IPersonService">
           <identity>
             <dns value="localhost" />
           </identity>
         </endpoint>
         <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
         <host>
           <baseAddresses>
             <add baseAddress="net.Tcp://localhost:6000/Pro.Service/PersonService/" />
           </baseAddresses>
         </host>
       </service>
     </services>
   </system.serviceModel>
 </configuration>



 在以上例子中,只在netTcpBincding绑定中加入了enable与inactivityTimeout两个最常用的功能,其意义只在于打开可靠性会话功能,把超时时间设置为10秒(定制10秒的超时时间,其用意是在于测试在10秒后再次调用服务对象,对象是否会抛出错误提示)。


客户端


新建一个网站项目,添加对PersonService服务的引用,在页面加入一个Label控件与一个Button控件,在Button的onClick方法调用PersonService服务。


<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/C#" runat="server">
        protected void btn1_Click(object sender, EventArgs e)
        {
            //注意在调用完成后把服务销毁
            using (PersonService.PersonServiceClient personService = new PersonService.PersonServiceClient())
            {
                Pro.Model.Person person = personService.GetPerson();
                Label1.Text = person.Name;
            }
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
      <asp:Label ID="Label1" runat="server"></asp:Label>
      <asp:Button ID="btn1" runat="server"  Text="Button"  OnClick="btn1_Click"/>
    </div>
    </form>
</body>
</html>




配置客户端文件,打开可靠性会话功能,注意把超时时间设置为10秒,与服务器的配置同步。在常用的服务处理页面,使用单体模式或者静态对象,在一定程序上可以减少服务器的负荷,提高效率。值得注意的是,如果使用单体模式,当服务启动10秒后,如果并未被再次调用,那下次调用时,系统将显示错误信息:“通信对象 System.ServiceModel.Channels.ServiceChannel 无法用于通信,因为其处于‘出错’状态”。所以,在配置“超时时间”时,应该注意控制时间的长短。


为了避免出现以上错误,在下建议在调用不经常使用的服务之时,应该把服务对象及时销毁,下次调用时重新建立一个服务对象。(可参考“注意事项”)


<configuration>
     <system.web>
         <compilation debug="true" targetFramework="4.0"/>
     </system.web>
     <system.serviceModel>
         <bindings>
             <netTcpBinding>
                 <binding name="NetTcpBinding_IPersonService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00"
                      sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                      hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536"
                      maxConnections="10" maxReceivedMessageSize="65536">
                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
                      <!--启动可靠性会话,把过期时间设置为10秒-->
                     <reliableSession inactivityTimeout="00:00:10" enabled="true"/>
                     <security mode="Transport">
                         <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
                         <message clientCredentialType="Windows"/>
                     </security>
                 </binding>
             </netTcpBinding>
         </bindings>
         <client>
             <endpoint address="net.tcp://localhost:6000/Pro.Service/PersonService/" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IPersonService" contract="PersonService.IPersonService" name="NetTcpBinding_IPersonService">
                 <identity>
                     <dns value="localhost"/>
                 </identity>
             </endpoint>
         </client>
     </system.serviceModel>
 </configuration>




三、注意事项

值得注意的一点是,在某些不常用到的页面中(比如在Login登录页面),客户往往在长时间内只调用一次服务,所以应该注意对服务对象进行及时销毁,否则客户再次登录时就会出来错误。


<html xmlns="http://www.w3.org/1999/xhtml">
 <head runat="server">
     <title></title>
     <script type="text/C#" runat="server">
         static PersonService.PersonServiceClient personService = new PersonService.PersonServiceClient();

         //只在页面初次调用时,personService才会被新建,如果超过限时没有被再次调用,就会出现错误
      
         protected void btn1_Click(object sender, EventArgs e)
         {
             Pro.Model.Person person = personService.GetPerson();
             Label1.Text = person.Name;
         }
     </script>
 </head>
 <body>
     <form id="form1" runat="server">
     <div>
       <asp:Label ID="Label1" runat="server"></asp:Label>
       <asp:Button ID="btn1" runat="server"  Text="Button"  OnClick="btn1_Click"/>
     </div>
     </form>
 </body>
 </html>



来源:http://www.cnblogs.com/leslies2/archive/2011/08/08/2129422.html


本文来源:
上一篇 下一篇