WCF揭秘——可靠性会话功能
WCF揭秘——可靠性会话功能
Windows Communication Foundation (WCF) 可靠性会话是一个如 WS-ReliableMessaging 协议所定义的 SOAP 可靠消息传递的实现。它在绑定层保证消息只会被传送一次,并能确定消息之间的传输顺序。它的特性在于保证了传输过程中消息不会丢失或者错位,在连接掉线的时候,它会重新连接服务器,连接次数可在配置文件中设定,当在连接失败的时候,能自动释放对话所占用的资源。 系统有多个绑定支持可靠性会话功能:wsHttpBinding、wsDualHttpBinding、wsFederationBinding、netTcpBinding
一、可靠性会话
Windows Communication Foundation (WCF) 可靠性会话是一个如 WS-ReliableMessaging 协议所定义的 SOAP 可靠消息传递的实现。它在绑定层保证消息只会被传送一次,并能确定消息之间的传输顺序。它的特性在于保证了传输过程中消息不会丢失或者错位,在连接掉线的时候,它会重新连接服务器,连接次数可在配置文件中设定,当在连接失败的时候,能自动释放对话所占用的资源。
系统有多个绑定支持可靠性会话功能:wsHttpBinding、wsDualHttpBinding、wsFederationBinding、netTcpBinding、netNamedPipesBinding。其中wsHttpBinding、wsFederationBinding、netTcpBinding在默认情况下可靠性会话功能是关闭。而wsDualHttpBinding、netNamedPipesBinding则默认支持可靠性功能。
二、开发实例
可靠性会话功能可以通过代码绑定,也可以通过config配置统一绑定,值得注意的是服务器端要与客户端的配置必须保持一致,避免出现冲突。下面以netTcpBinding契约为例子,说明一下可靠性会话的功能。首先建立数据契约Person,和服务契约PersonService,客户端通过GetPerson方法获取Person对象。
- 服务器端
1 namespace Pro.Model 2 { 3 //建立数据契约 4 [DataContract] 5 publicclass Person 6 { 7 [DataMember] 8 publicint ID 9 { 10 get; 11 set; 12 } 13 14 [DataMember] 15 publicstring Name 16 { 17 get; 18 set; 19 } 20 21 [DataMember] 22 publicint Age 23 { 24 get; 25 set; 26 } 27 } 28 } 29 30 namespace Pro.Service 31 { 32 // 建立服务契约接口“IPersonService”。 33 [ServiceContract] 34 publicinterface IPersonService 35 { 36 [OperationContract] 37 Person GetPerson(); 38 } 39 40 // 实现服务契约“PersonService”。 41 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 42 publicclass 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 staticvoid 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,用于控制数据缓冲区数量。
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 16 17 binding> 18 netTcpBinding> 19 bindings> 20 21 <services> 22 <service name="Pro.Service.PersonService"> 23 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 xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>title> <script type="text/C#" runat="server"> protectedvoid 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 无法用于通信,因为其处于‘出错’状态”。所以,在配置“超时时间”时,应该注意控制时间的长短。
为了避免出现以上错误,在下建议在调用不经常使用的服务之时,应该把服务对象及时销毁,下次调用时重新建立一个服务对象。(可参考“注意事项”)
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 11 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登录页面),客户往往在长时间内只调用一次服务,所以应该注意对服务对象进行及时销毁,否则客户再次登录时就会出来错误。
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head runat="server"> 3 <title>title> 4 <script type="text/C#" runat="server"> 5 static PersonService.PersonServiceClient personService =new PersonService.PersonServiceClient(); 6 //只在页面初次调用时,personService才会被新建,如果超过限时没有被再次调用,就会出现错误 7 8 protectedvoid btn1_Click(object sender, EventArgs e) 9 { 10 Pro.Model.Person person = personService.GetPerson(); 11 Label1.Text = person.Name; 12 } 13 script> 14 head> 15 <body> 16 <form id="form1" runat="server"> 17 <div> 18 <asp:Label ID="Label1" runat="server">asp:Label> 19 <asp:Button ID="btn1" runat="server" Text="Button" OnClick="btn1_Click"/> 20 div> 21 form> 22 body> 23 html>
- ActionScript 3.0 记要(2): 类与接口
- 理解浮点数的储存规则
- 运维安全应该怎么做?
- 通过消息跨进程发送与接收 TCopyDataStruct 数据 - 回复 "skymesh"
- 使用多窗体时, 关于节约内存和加快启动速度的思考与尝试
- 从哪查找当前程序所有可用的环境变量?
- 关于 "高位" 与 "低位" - 回复 "Lovemit" 的问题
- 关于 OnMouseWheelDown、OnMouseWheelUp 等事件的简单例子 - 回复
- 如何用弹出窗口显示进度 - 回复
- 把字节数组读入到流 - 回复
- 动态调整 TBitBtn 上的图片 - 回复
- WCF揭秘——简单的WCF开发实例
- 汇编指令速查
- 如何让 TreeView 的列表项携带数据、并读出或删除这个数据 - 回复
- 获取 "斐波那契数列" 的函数
- 枚举可以这样遍历
- 如何用产品思维摆地摊月入三万?
- 简单的 "双缓冲" 绘图的例子 - 回复 "TookiQ" 的问题
- WCF揭秘——使用AJAX+WCF服务进行页面开发
- 使用WCF实现SOA面向服务编程—— 架构设计