在上面一篇文章中,我們對不同版本的IIS,以及ASP.NET得的實現機制進行了詳細而深入的分析。在介紹IIS7.0的時候,我們談到,HTTP.SYS+W3SVC實現了基於HTTP的請求監聽,在此基礎上引入了以下三組網絡監聽器(Listener)和監聽適配器(Adapter),實現了基於TCP、Named Pipes和MSMQ的網絡監聽,圖1揭示了IIS7的總體結構。
TCPListener|TCP Listener Adapter
NamedPipes Listener|Named Pipes Listener Adapter
MSMQ Listener|MSMQ Listener Adapter
圖1 IIS 7總體架構
由於IIS 7提供了基於非HTTP網絡協議的監聽支持,那麼就意味著當我們當我們通過IIS進行WCF服務寄宿(Hosting)的時候,可以采用非HTTP的通信方式。在本篇文章中,我們將通過一個簡單實例介紹進行非HTTP的IIS服務寄宿,Source Code下載WasHostingDemo.zip。
由於IIS 7在本質上通過WAS(Windows Process Activation Service)實現了非HTTP的請求監聽,我們也可以將這種方式的服務寄宿稱為基於WAS的服務寄宿。在本實例中,我們通過IIS 7實現基於TCP的服務寄宿,圖2表示實例應用在VS2008種的解決方案結構。其中,Class Library類型的項目Contracts用於定義服務契約;而Services則用於定義具體的服務;Console應用項目Client模擬客戶端。此外,Services對應目錄被映射為IIS相應站點下的某個Web應用,虛擬目錄名稱為WasHostingDemo。
圖2 基於TCP的IIS服務寄宿實例在VS2008中的解決方案結構
步驟一:定義服務契約和服務
本實例仍然采用我們熟悉的計算服務的例子,在Contracts項目下,定義了接口ICalculator代表計算服務的服務契約。
1: using System.ServiceModel;
2:
3: namespace Artech.WasHostingDemo.Contracts
4: {
5: [ServiceContract(Namespace="http://www.artech.com/")]
6: public interface ICalculator
7: {
8: [OperationContract]
9: double Add(double x, double y);
0: }
1: }
在Services項目中,實現了ICalculator接口,提供服務的實現:
1: using Artech.WasHostingDemo.Contracts;
2:
3: namespace Artech.WasHostingDemo.Services
4: {
5: public class CalculatorService:ICalculator
6: {
7: #region ICalculator Members
8:
9: public double Add(double x, double y)
0: {
1: return x + y;
2: }
3:
4: #endregion
5: }
6: }
和普通基於HTTP的IIS服務寄宿一樣,我們需要為WCF服務創建相應的.SVC文本文件,該文件一般僅僅包含一個<%@ ServiceHost%>指令。簡單起見,我僅僅添加了唯一一個必需的Service屬性(Attribute)。我把該文件命名為CalculatorService.svc,下面是該.SVC的全部內容:
<%@ ServiceHost Service="Artech.WasHostingDemo.Services.CalculatorService,Artech.WasHostingDemo.Services"%>
然後,將Services所在的目錄映射為IIS下的虛擬目錄。在本例中,在IIS 7的Default Web Site站點下,創建了一個命名為WasHostingDemo的Web應用,並將其物理地址指定為Services項目所在的目錄。然後在根目錄下創建一個Web.config,配置WCF服務寄宿相關的設置。整個WCF配置如下,Binding類型指定為NetTcpBinding。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <services>
5: <service name="Artech.WasHostingDemo.Services.CalculatorService">
6: <endpoint address="" binding="netTcpBinding" bindingConfiguration=""
7: contract="Artech.WasHostingDemo.Contracts.ICalculator" />
8: </service>
9: </services>
0: </system.serviceModel>
1: </configuration>
注:由於ASP.NET應用在運行的時候默認從根目錄下的Bin子目錄加載Assembly,而Services項目默認編譯的目標目錄為Bin\Debug|Release,所以我們需要通過修改項目屬性將編譯的目標目錄設為Bin。
步驟二:為站點設置TCP綁定,為Web應用添加支持協議
進行非HTTP的服務寄宿是WAS為WCF提供的最顯著的特性。由於在默認的情況下,IIS僅僅支持對於HTTP請求的處理,我們需要相應的方式對IIS相關配置進行相關的修改,從而改變IIS默認的請求處理行為。在上面我們說過,IIS 7.0廣泛采用了基於XML文件的配置方式,所以最終極的方式就是直接修改相應的配置文件。但是,直接修改配置文件的方式,出錯的頻率很高,對於很多的配置,我們都可以直接通過IIS管理器進行相應的修改。此外,我們可以選擇通過命令行的方式修改相應的配置,IIS為我們提供了一系列的命令。
WAS的配置保存在配置文件applicationHost.config中,該文件保存在%windir%\system32\inetsrv\config目錄中。為了實現基於非HTTP的服務寄宿,首先需要做的是為WCF Service的寄宿應用所在的Web Site添加非相應非HTTP協議的站點綁定(site binding),該操作可以通過執行Appcmd.exe命名實現,該命名存放在%windir%\system32\inetsrv\目錄中。
為了使寄宿WCF服務的Web站點具有基於TCP的監聽能力,我們可以通過下面的命名行為該站點(Default Web Site)添加基於TCP的綁定,指定監聽端口為808(默認端口)。
appcmd.exe set site "Default Web Site" -+bindings.[protocol='net.tcp',bindingInformation='808:*']
站點綁定添加於修改也可以直接通過IIS管理器進行:選擇相應站點=〉在右邊的部分“Bindings”=〉在彈出的Site Bindings對話框中可以添加新的站點綁定和編輯現有的站點綁定,如圖3所示。
圖3 通過IIS管理器設置站點綁定
在站點級別非HTTP綁定存在的情況下,你還可在應用級別控制對非HTTP協議的支持。在默認的情況下,Web應用並不提供對非HTTP協議的支持,你需要通過AppCmd.exe為應用添加對於某個非HTTP協議支持的能力。通過下面的配置對默認站點下的WasHostingDemo應用添加了對net.tcp支持的能力。
appcmd.exe set app "Default Web Site/WasHostingDemo" /enabledProtocols:net.tcp
步驟三:創建客戶端程序進行服務調用
對於調用非HTTP協議的IIS寄宿服務的客戶端來說,和普通的WCF服務調用完全一樣,下面是服務調用代碼和相關的配置。由於,客戶端程序通過訪問WCF服務的.SVC文件的方式進行服務的調用,所以在相應終結點中的地址為.SVC所在的地址。
1: using System;
2: using System.ServiceModel;
3: using Artech.WasHostingDemo.Contracts;
4:
5: namespace Artech.WasHostingDemo.Client
6: {
7: class Program
8: {
9: static void Main(string[] args)
0: {
1: using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice"))
2: {
3: ICalculator calculator = channelFactory.CreateChannel();
4: using (calculator as IDisposable)
5: {
6: try
7: {
8: Console.WriteLine("x + y = {2} when x = {0} and y = {1}", 1, 2, calculator.Add(1, 2));
9: }
0: catch (CommunicationException)
1: {
2: (calculator as ICommunicationObject).Abort();
3: throw;
4: }
5: catch (TimeoutException)
6: {
7: (calculator as ICommunicationObject).Abort();
8: throw;
9: }
0: }
1: }
2: }
3: }
4: }
1: <?xml version="1.0" encoding="utf-8" ?>
2: <configuration>
3: <system.serviceModel>
4: <client>
5: <endpoint address="net.tcp://127.0.0.1/WasHostingDemo/CalculatorService.svc"
6: binding="netTcpBinding" bindingConfiguration="" contract="Artech.WasHostingDemo.Contracts.ICalculator"
7: name="calculatorservice" />
8: </client>
9: </system.serviceModel>
10: </configuration>
通過運行客戶端程序,你將得到如下的輸出:
1: x + y = 3 when x = 1 and y = 2