WCF 采用net.tcp协议实践
概述
与Socket相比,WCF真是爽得不得了,其基本指导思想为SOA——面向服务。
其基本配置在于ABC(Address,Binding,Contract),通常,只要这三个因素配置对了,那么,基本上就无限接近目标了。
剩下的配置,就可能是行为(Behavior),安全(Security)等。
在所有绑定中,为什么要选择net.tcp,是因为其比较快(我这也是道听途说,究竟有多快,没有进行过测试);但是,缺点就是,net.tcp方式只能是WCF对WCF的通信。
而其繁琐复杂的配置,网上已经有诸多工程师做了很多无私的奉献。
步骤
原文参考:http://hi.baidu.com/guolulang/item/b5bdb01ccb23810ce65c36d6
http://www.cnblogs.com/Gyoung/archive/2012/12/11/2812555.html
Step1:设置“打开或关闭Windows功能”
打开红色框内的功能
Step2:设置IIS
选中Default Web Site ——点击“绑定”——确保网站绑定对话框中有“net.tcp”(默认端口号808),如果没有,则“添加”
选中项目——高级设置——确保有“net.tcp”
Step3:设置“服务”
Step4:设置配置文件
只需将下文中的******替换即可。
S4.1服务端模板
替换Address(主机名+端口+文件路径形式的名称);
替换Contract(服务接口全名)
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.serviceModel> <!--描述绑定--> <bindings> <netTcpBinding> <binding name="netTcpBindConfig" closeTimeout="00:30:00" openTimeout="00:30:00" receiveTimeout="00:30:00" sendTimeout="00:30:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxConnections="10" maxReceivedMessageSize="2147483647"> <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> <reliableSession ordered="true" inactivityTimeout="00:01:00" enabled="false" /> <security mode="None"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"></transport> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings> <!--描述服务--> <services> <service name="DataSync.Services.DataSyncServiceImpl" behaviorConfiguration="WFServiceBehavior"> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:808/DSServiceImpl"/> </baseAddresses> </host> <endpoint address="" contract="DataSync.Interfaces.IDataSyncEntry" binding="netTcpBinding" bindingConfiguration="netTcpBindConfig" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <!--描述行为--> <behaviors> <serviceBehaviors> <behavior name="WFServiceBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <dataContractSerializer maxItemsInObjectGraph="6553600"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <!-- 若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。 在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。 --> <directoryBrowse enabled="true"/> </system.webServer> <system.web> <compilation debug="true" targetFramework="4.0" /> </system.web> </configuration>
S4.2客户端模板
替换Address(指定寄宿的地址,如****/***.svc,而不是上文的DSServiceImpl);
替换Contract(服务接口全名)
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding name="NetTcpBinding_IDataSyncEntry"> <security mode="None" /> </binding> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://75wojoax/WcfWays/DataSyncServiceImpl.svc" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IDataSyncEntry" contract="Remote.IDataSyncEntry" name="NetTcpBinding_IDataSyncEntry" /> </client> </system.serviceModel> </configuration>
问题
P1 需重启IIS
问题描述:未能从程序集“System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”中加载类型“System.ServiceModel.Activation.HttpModule”。
解决办法(执行以下命令,以重启IIS):
如果安装了 .NET Framework 4,随后启用了 .NET Framework 3.5 WCF HTTP 激活,则会发生此错误。若要解决该问题,请在 Visual Studio 2010 命令提示符下运行下面的命令行: aspnet_regiis.exe -i -enable 参见:http://msdn.microsoft.com/zh-cn/library/aa751852.aspx |
P2 需匹配的协议
问题描述:找不到具有绑定 NetTcpBinding 的终结点的与方案 net.tcp 匹配的基址。注册的基址方案是 [http]。
解决方案:确保服务端和客户端均使用NetTcpBinding协议。
参考:http://www.cnblogs.com/liulun/archive/2011/11/25/2263873.html
P3需匹配的协议
问题描述:无法调度消息,因为终结点地址“net.tcp://localhost/DataSyncServiceImpl.svc”上的服务对该地址的协议不可用。
解决方案:
1)确保服务端和客户端均使用NetTcpBinding协议;
2)如果服务端使用了安全配置,如
<security mode="None"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"></transport> <message clientCredentialType="Windows" /> </security>
则,客户端也需要使用同类的协议,如
<bindings> <netTcpBinding> <binding name="NetTcpBinding_IDataSyncEntry"> <security mode="None" /> </binding> </netTcpBinding> </bindings>
或者代码中
var binding = new NetTcpBinding(); binding.Security = new NetTcpSecurity() { Mode = SecurityMode.None };
P4 契约返回DataTable
问题描述:使用DataTable作为返回值
解决方案:
1) 网上传说——使用命名的DataTable,即为DataTable的TableName赋一个名称(试了一下,不行);
2) 传递DataSet可以。
public System.Data.DataSet TestDataTable() { DataTable dt = new DataTable("result"); dt.TableName = "navigateData"; dt.Columns.Add("Name",typeof(string)); var dr = dt.NewRow(); dr["Name"] = "pz"; dt.Rows.Add(dr); dr = dt.NewRow(); dr["Name"] = "pz2"; dt.Rows.Add(dr); var ds = new DataSet(); ds.Tables.Add(dt); return ds; }
P5 使用Channel Factory
问题描述:客户端可以直接“引用服务”以生成***Client,但是,这不利于修改。
当修改了接口之后,没有办法及时通知到客户端,除了“更新服务饮引用”之外。
解决方案:客户端引用服务接口,并使用Channel Factory进行解耦,则客户端只依赖接口。
public static DataSync.Interfaces.IDataSyncEntry CreateDataSyncEntryServices() { EndpointAddress addr = new EndpointAddress("net.tcp://75wojoax/WcfWays/DataSyncServiceImpl.svc"); var binding = new NetTcpBinding(); binding.Security = new NetTcpSecurity() { Mode = SecurityMode.None }; var channel = new ChannelFactory<DataSync.Interfaces.IDataSyncEntry>(binding, addr); var service = channel.CreateChannel(); return service; }