WCF揭秘——可靠性会话功能 ._.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > WCF揭秘——可靠性会话功能 .

WCF揭秘——可靠性会话功能 .

 2013/9/7 21:11:44  蒋叶湖  博客园  我要评论(0)
  • 摘要:一、可靠性会话WindowsCommunicationFoundation(WCF)可靠性会话是一个如WS-ReliableMessaging协议所定义的SOAP可靠消息传递的实现。它在绑定层保证消息只会被传送一次,并能确定消息之间的传输顺序。它的特性在于保证了传输过程中消息不会丢失或者错位,在连接掉线的时候,它会重新连接服务器,连接次数可在配置文件中设定,当在连接失败的时候,能自动释放对话所占用的资源。系统有多个绑定支持可靠性会话功能:wsHttpBinding
  • 标签:功能 WCF

一、可靠性会话

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

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

二、开发实例

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

  • 服务器端

 

[csharp] view plaincopyprint?
    class="dp-c">
  1. namespace Pro.Model  
  2.  2 {  
  3.  3     //建立数据契约   
  4.  4     [DataContract]  
  5.  5     public class Person  
  6.  6     {  
  7.  7         [DataMember]  
  8.  8         public int ID  
  9.  9         {  
  10. 10             get;  
  11. 11             set;  
  12. 12         }  
  13. 13   
  14. 14         [DataMember]  
  15. 15         public string Name  
  16. 16         {  
  17. 17             get;  
  18. 18             set;  
  19. 19         }  
  20. 20   
  21. 21         [DataMember]  
  22. 22         public int Age  
  23. 23         {  
  24. 24             get;  
  25. 25             set;  
  26. 26         }  
  27. 27     }  
  28. 28 }  
  29. 29   
  30. 30 namespace Pro.Service  
  31. 31 {  
  32. 32     // 建立服务契约接口“IPersonService”。   
  33. 33     [ServiceContract]  
  34. 34     public interface IPersonService  
  35. 35     {  
  36. 36         [OperationContract]  
  37. 37         Person GetPerson();  
  38. 38     }  
  39. 39   
  40. 40     // 实现服务契约“PersonService”。   
  41. 41     [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]  
  42. 42     public class PersonService : IPersonService  
  43. 43     {  
  44. 44         public Person GetPerson()  
  45. 45         {  
  46. 46             Person person = new Person();  
  47. 47             person.ID = 0;  
  48. 48             person.Name = "Leslie";  
  49. 49             person.Age = 31;  
  50. 50               
  51. 51             return person;  
  52. 52         }  
  53. 53     }  
  54. 54   
  55. 55     class Program  
  56. 56     {  
  57. 57         //启动服务   
  58. 58         static void Main(string[] args)  
  59. 59         {  
  60. 60             Console.WriteLine("Service star!");  
  61. 61             ServiceHost host1 = new ServiceHost(typeof(PersonService));  
  62. 62             host1.Open();  
  63. 63             Console.ReadKey();  
  64. 64             host1.Close();  
  65. 65         }  
  66. 66     }  
  67. 67 }  
namespace Pro.Model
 2 {
 3     //建立数据契约
 4     [DataContract]
 5     public class Person
 6     {
 7         [DataMember]
 8         public int ID
 9         {
10             get;
11             set;
12         }
13 
14         [DataMember]
15         public string Name
16         {
17             get;
18             set;
19         }
20 
21         [DataMember]
22         public int Age
23         {
24             get;
25             set;
26         }
27     }
28 }
29 
30 namespace Pro.Service
31 {
32     // 建立服务契约接口“IPersonService”。
33     [ServiceContract]
34     public interface IPersonService
35     {
36         [OperationContract]
37         Person GetPerson();
38     }
39 
40     // 实现服务契约“PersonService”。
41     [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
42     public class PersonService : IPersonService
43     {
44         public Person GetPerson()
45         {
46             Person person = new Person();
47             person.ID = 0;
48             person.Name = "Leslie";
49             person.Age = 31;
50             
51             return person;
52         }
53     }
54 
55     class Program
56     {
57         //启动服务
58         static void Main(string[] args)
59         {
60             Console.WriteLine("Service star!");
61             ServiceHost host1 = new ServiceHost(typeof(PersonService));
62             host1.Open();
63             Console.ReadKey();
64             host1.Close();
65         }
66     }
67 }

 

添加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,用于控制数据缓冲区数量。

 

[html] view plaincopyprint?
  1.  1 <configuration>  
  2.  2   <system.serviceModel>  
  3.  3     <behaviors>  
  4.  4       <serviceBehaviors>  
  5.  5         <behavior name="">  
  6.  6           <serviceMetadata httpGetEnabled="false" />  
  7.  7           <serviceDebug includeExceptionDetailInFaults="true" />  
  8.  8         </behavior>  
  9.  9       </serviceBehaviors>  
  10. 10     </behaviors>  
  11. 11   
  12. 12     <bindings>  
  13. 13       <netTcpBinding>  
  14. 14         <binding name="defaultNetTcpBinding">  
  15. 15           <!--打开可靠性会话功能,把过期时间配置为10秒-->  
  16. 16           <reliableSession enabled="true" inactivityTimeout="00:00:10"/>  
  17. 17         </binding>  
  18. 18       </netTcpBinding>  
  19. 19     </bindings>  
  20. 20   
  21. 21     <services>  
  22. 22       <service name="Pro.Service.PersonService">  
  23. 23         <!--绑定defaultNetTcpBinding-->  
  24. 24         <endpoint address=""  bindingConfiguration="defaultNetTcpBinding" binding="netTcpBinding" contract="Pro.Service.IPersonService">  
  25. 25           <identity>  
  26. 26             <dns value="localhost" />  
  27. 27           </identity>  
  28. 28         </endpoint>  
  29. 29         <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />  
  30. 30         <host>  
  31. 31           <baseAddresses>  
  32. 32             <add baseAddress="net.Tcp://localhost:6000/Pro.Service/PersonService/" />  
  33. 33           </baseAddresses>  
  34. 34         </host>  
  35. 35       </service>  
  36. 36     </services>  
  37. 37   </system.serviceModel>  
  38. 38 </configuration>  
 1 <configuration>
 2   <system.serviceModel>
 3     <behaviors>
 4       <serviceBehaviors>
 5         <behavior name="">
 6           <serviceMetadata httpGetEnabled="false" />
 7           <serviceDebug includeExceptionDetailInFaults="true" />
 8         </behavior>
 9       </serviceBehaviors>
10     </behaviors>
11 
12     <bindings>
13       <netTcpBinding>
14         <binding name="defaultNetTcpBinding">
15           <!--打开可靠性会话功能,把过期时间配置为10秒-->
16           <reliableSession enabled="true" inactivityTimeout="00:00:10"/>
17         </binding>
18       </netTcpBinding>
19     </bindings>
20 
21     <services>
22       <service name="Pro.Service.PersonService">
23         <!--绑定defaultNetTcpBinding-->
24         <endpoint address=""  bindingConfiguration="defaultNetTcpBinding" binding="netTcpBinding" contract="Pro.Service.IPersonService">
25           <identity>
26             <dns value="localhost" />
27           </identity>
28         </endpoint>
29         <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
30         <host>
31           <baseAddresses>
32             <add baseAddress="net.Tcp://localhost:6000/Pro.Service/PersonService/" />
33           </baseAddresses>
34         </host>
35       </service>
36     </services>
37   </system.serviceModel>
38 </configuration>

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

  • 客户端

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

 

[html] view plaincopyprint?
  1. <html xmlns="http://www.w3.org/1999/xhtml">  
  2. <head runat="server">  
  3.     <title></title>  
  4.     <script type="text/C#" runat="server">  
  5.         protected void btn1_Click(object sender, EventArgs e)  
  6.         {  
  7.             //注意在调用完成后把服务销毁  
  8.             using (PersonService.PersonServiceClient personService = new PersonService.PersonServiceClient())  
  9.             {  
  10.                 Pro.Model.Person person = personService.GetPerson();  
  11.                 Label1.Text = person.Name;  
  12.             }  
  13.         }  
  14.     </script>  
  15. </head>  
  16. <body>  
  17.     <form id="form1" runat="server">  
  18.     <div>  
  19.       <asp:Label ID="Label1" runat="server"></asp:Label>  
  20.       <asp:Button ID="btn1" runat="server"  Text="Button"  OnClick="btn1_Click"/>  
  21.     </div>  
  22.     </form>  
  23. </body>  
  24. </html>  
<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 无法用于通信,因为其处于‘出错’状态”。所以,在配置“超时时间”时,应该注意控制时间的长短。

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

 

[html] view plaincopyprint?
  1.  1 <configuration>  
  2.  2     <system.web>  
  3.  3         <compilation debug="true" targetFramework="4.0"/>  
  4.  4     </system.web>  
  5.  5     <system.serviceModel>  
  6.  6         <bindings>  
  7.  7             <netTcpBinding>  
  8.  8                 <binding name="NetTcpBinding_IPersonService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00"   
  9.                       sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"   
  10.                       hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536"   
  11.                       maxConnections="10" maxReceivedMessageSize="65536">  
  12.  9                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>  
  13. 10                      <!--启动可靠性会话,把过期时间设置为10秒-->  
  14. 11                     <reliableSession inactivityTimeout="00:00:10" enabled="true"/>  
  15. 12                     <security mode="Transport">  
  16. 13                         <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>  
  17. 14                         <message clientCredentialType="Windows"/>  
  18. 15                     </security>  
  19. 16                 </binding>  
  20. 17             </netTcpBinding>  
  21. 18         </bindings>  
  22. 19         <client>  
  23. 20             <endpoint address="net.tcp://localhost:6000/Pro.Service/PersonService/" binding="netTcpBinding"   
  24.                 bindingConfiguration="NetTcpBinding_IPersonService" contract="PersonService.IPersonService" name="NetTcpBinding_IPersonService">  
  25. 21                 <identity>  
  26. 22                     <dns value="localhost"/>  
  27. 23                 </identity>  
  28. 24             </endpoint>  
  29. 25         </client>  
  30. 26     </system.serviceModel>  
  31. 27 </configuration>  
 1 <configuration>
 2     <system.web>
 3         <compilation debug="true" targetFramework="4.0"/>
 4     </system.web>
 5     <system.serviceModel>
 6         <bindings>
 7             <netTcpBinding>
 8                 <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">
 9                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
10                      <!--启动可靠性会话,把过期时间设置为10秒-->
11                     <reliableSession inactivityTimeout="00:00:10" enabled="true"/>
12                     <security mode="Transport">
13                         <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
14                         <message clientCredentialType="Windows"/>
15                     </security>
16                 </binding>
17             </netTcpBinding>
18         </bindings>
19         <client>
20             <endpoint address="net.tcp://localhost:6000/Pro.Service/PersonService/" binding="netTcpBinding" 
                bindingConfiguration="NetTcpBinding_IPersonService" contract="PersonService.IPersonService" name="NetTcpBinding_IPersonService">
21                 <identity>
22                     <dns value="localhost"/>
23                 </identity>
24             </endpoint>
25         </client>
26     </system.serviceModel>
27 </configuration>

 

三、注意事项

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

 

[html] view plaincopyprint?
  1. <html xmlns="http://www.w3.org/1999/xhtml">  
  2.  2 <head runat="server">  
  3.  3     <title></title>  
  4.  4     <script type="text/C#" runat="server">  
  5.  5         static PersonService.PersonServiceClient personService = new PersonService.PersonServiceClient();  
  6.  6         //只在页面初次调用时,personService才会被新建,如果超过限时没有被再次调用,就会出现错误  
  7.  7         
  8.  8         protected void btn1_Click(object sender, EventArgs e)  
  9.  9         {  
  10. 10             Pro.Model.Person person = personService.GetPerson();  
  11. 11             Label1.Text = person.Name;  
  12. 12         }  
  13. 13     </script>  
  14. 14 </head>  
  15. 15 <body>  
  16. 16     <form id="form1" runat="server">  
  17. 17     <div>  
  18. 18       <asp:Label ID="Label1" runat="server"></asp:Label>  
  19. 19       <asp:Button ID="btn1" runat="server"  Text="Button"  OnClick="btn1_Click"/>  
  20. 20     </div>  
  21. 21     </form>  
  22. 22 </body>  
  23. 23 </html>  
发表评论
用户名: 匿名