摘要 : 从IIS 7 开始, IIS增加了对非HTTP协议的支持. 因此, 自IIS 7之后, 可以将NetTcpBinding等非HTTP协议的Bindings直接寄宿在IIS上面. 本文将介绍如何在IIS上配置WCF NetTcpBinding, 并且对其工作的方式进行比较深入的讨论.
Windows Process Activation Service
下图是IIS监听在HTTP协议上的工作方式. 对HTTP协议的监听是在内核模式下的HTTP.sys的帮助下完成
从IIS7开始,IIS还加入了对非HTTP协议的支持。对于那些采用非HTTP协议,但是又需要部署在IIS里面,从而利用IIS优秀的管理功能的服务来说,比如WCF服务,可谓一大福音。IIS7可以支持多种非HTTP协议,比如net.tcp,net.msmq, net.pipe等。由于HTTP.sys并不会监听非HTTP协议的端口. 对于非HTTP协议, 则有各自的Windows Serivce来进行监听. 例如Net.Tcp协议, 则是由Net.Tcp Port Sharing Service和Net.Tcp Listener Adapter服务进行监听, 并且寄宿在SMSvcHost.exe中.
进过拆分之后, WAS不仅处理HTTP请求,还可以处理非HTTP协议的请求。HTTP请求是由Http.sys截获的,并且在传递给WAS之前,就已经传递给w3svc中的HTTP管理器,但是,其他请求都是通过WAS侦听器的适配器接口转发给配置管理器和进程管理器的,而没有经过w3svc。
关于 WAS的介绍可以参考这里 :
http://msdn.microsoft.com/en-us/library/ms734677(v=vs.110).aspx
http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/02/08/iis-7-support-for-non-http-protocols.aspx
为了让IIS支持net.tcp,必须先安装WAS(Windows Process Activation Service),即windows进程激活服务。
打开控制面板--程序和功能--打开或关闭windows功能,安装WAS,如图:
安装完毕后在Services窗口中可以到到如下服务:Windows Process Activation Service;Net.Msmq Listener Adapter;Net.Pipe Listener Adapter;Net.Tcp Listener Adapter;Net.Tcp Port Sharing Service.这几个服务。确定Net.Tcp Listener Adapter 与Net.Tcp Port Sharing Service是否已经启动。
同样, 也需要检查WCF是否启用了Non-Http的支持. .Net Framework 3.5和 .Net Framework 4.5分别有各自的支持.
不过上述的Services只会存在一个, 如果服务器上只有.Net Framework 3.5本版的被启用, 则这些Services则只能使用3.5版本的DLL. 如果.Net Framework 4.5版本一旦被启用, 无论是否同时启用了3.5版本, 则会使用4.5版本. 可以通过服务所使用的SMSvcHost.exe来判断实际使用了那一个版本.
IIS 上的配置
在IIS中,选中你的网站,然后在右边的操作菜单栏中单击绑定,会弹出一个“网站绑定”窗口,点击添加,类型选择net.tcp
选择你的网站,点击“高级设置”,弹出的的窗体中,在“已启用的协议”一栏中手动添加:net.tcp. 做完这一步之后, 该网站即增加了对net.tcp协议的支持.
示例
示例是用VS2012新建的WCF模板.
1 public class Service1 : IService1 2 { 3 public string GetData(int value) 4 { 5 return string.Format("You entered: {0}", value); 6 } 7 8 public CompositeType GetDataUsingDataContract(CompositeType composite) 9 { 10 if (composite == null) 11 { 12 throw new ArgumentNullException("composite"); 13 } 14 if (composite.BoolValue) 15 { 16 composite.StringValue += "Suffix"; 17 } 18 return composite; 19 } 20 }
下面是使用了NetTcpBinding的WCF Service的配置.
<?xml version="1.0"?> <configuration> <appSettings> <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> </appSettings> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5"/> </system.web> <system.serviceModel> <bindings> <netTcpBinding> <binding name="NewBinding1" /> </netTcpBinding> </bindings> <services> <service name="NetTcpSite.Service1"> <endpoint binding="netTcpBinding" bindingConfiguration="NewBinding1" contract="NetTcpSite.IService1" /> <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration="" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the values below to false before deployment --> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <protocolMapping> <add binding="basicHttpsBinding" scheme="https" /> </protocolMapping> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> <directoryBrowse enabled="true"/> </system.webServer> </configuration>
由于WCF 4.5对默认配置进行了优化. 所以即使没有关于HTTP协议的任何配置, WCF Service默认情况下也能通过浏览器的方式访问到WSDL.
如果要访问NetTcpBinding的WCF Service则需要一个同样采用Net.TCP协议的客户端. 这里, 我使用了VS 2012来完成.
下面是WCF客户端的的配置和代码.
class Program { static void Main(string[] args) { using (NetTcpService.Service1Client proxy = new Service1Client()) { Console.WriteLine(proxy.GetData(10)); } Console.ReadLine(); } }
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <system.serviceModel> <bindings> <netTcpBinding> <binding name="NetTcpBinding_IService1" /> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://localhost/NetTcpSite/Service1.svc" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IService1" contract="NetTcpService.IService1" name="NetTcpBinding_IService1"> <identity> <servicePrincipalName value="host/LIGHTWEAPON.fareast.corp.microsoft.com" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>
我们进一步来观察是哪一个进程监听在Net.Tcp占用的808端口上. 从下图上可以验证出, 监听在808端口上的进程是2060. 这个进程ID是SMSvcHost.exe, 也就是上面提到的各种Services的宿主进程.