我們已經(jīng)知道,對于一個(gè)服務(wù)(接口),有A、B、C三個(gè)要素,通過(guò)他們可以被客戶(hù)端利用來(lái)調用,可是在服務(wù)端,它的結構是怎么樣的?
ServiceHost
WCF的服務(wù)可以有很多寄存環(huán)境,可是,不管在哪種環(huán)境,服務(wù)模型在宿主初始化,操作調用和消息處理方面,都提供一致的運行時(shí)體驗。ServiceHost類(lèi)型在這過(guò)程中扮演著(zhù)重要的角色。
簡(jiǎn)單的可以認為ServiceHost負責管理服務(wù)的通信信道的生存周期。
建立ServiceHost
一般使用public ServiceHost(Type serviceType, params Uri[] baseAddresses)構造方法建立ServicesHost。
參數:
Type serviceType --為實(shí)現了某些Contract的類(lèi)的類(lèi)型,為這個(gè)服務(wù)主機要host的服務(wù)。
params Uri[] baseAddresses --為任意數量的baseAddress。
Uri baseAddress = new Uri("http://localhost:8080/WCFService/Service");
//Instantiate new ServiceHost
myServiceHost = new ServiceHost(typeof(Service), baseAddress);
一個(gè)ServiceHost內只能駐留一個(gè)Service類(lèi),但是這個(gè)Service類(lèi)可以實(shí)現多個(gè)Contract,每個(gè)Contract都能通過(guò)一個(gè)或多個(gè)(不同的bind)Endpoint向客戶(hù)端暴露。
通過(guò)兩種方法給ServiceHost添加Endpoint
ServiceHost.AddServiceEndpoint
AddServiceEndpoint方法有8種重載,ServiceHost提供了四種:
ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address);
ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address);
ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address, Uri listenUri);
ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, Uri address, Uri listenUri);
ServiceHost的父類(lèi)ServiceHostBase也提供了四種:
ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address);
ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address);
ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, string address, Uri listenUri);
ServiceEndpoint AddServiceEndpoint(string implementedContract, Binding binding, Uri address, Uri listenUri);
其中參數implementedContract為Contract的完全名稱(chēng),即名稱(chēng)空間.類(lèi)名。
myServiceHost.AddServiceEndpoint(typeof(WCFService.IService), new BasicHttpBinding(), "");
ServiceHost.Description.AddServiceEndpoint
ServiceDescription是一個(gè)Service在內存中的一個(gè)完整描述。包括:EndPoints和Behaviors。
ServiceEndpoint myServiceEndpoint = new ServiceEndpoint(ContractDescription.GetContract(typeof(WCFService.IService)), new BasicHttpBinding(), new EndpointAddress(baseAddress));
myServiceHost.Description.Endpoints.Add(myServiceEndpoint);
視需要給ServiceHost添加behavior
ServiceHost. Behaviors是一個(gè) IServiceBehavior類(lèi)型的對象集合。
IserviceBehavior提供了一個(gè)在整個(gè)服務(wù)范圍內修改或則插入定制擴展的機制。
如果需要把服務(wù)通過(guò)WSDL對外暴露對服務(wù)的Metadata描述,就需要加一個(gè)ServiceMetadataBehavior類(lèi)型的Behavior:
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri("http://localhost:8001/");
myServiceHost.Description.Behaviors.Add(behavior); // myServiceHost是ServiceHost實(shí)例
一個(gè)較規范(正確的)ServiceHost描述應該是這樣的:

EndPointListener偵聽(tīng)器包含了listening address,message filtering和duspatch。他們獨贏(yíng)ServiceEndpoint中的EndPointAddress、Contract、Binding。在EndpointListener中,還包含了一個(gè)Channel Stack,專(zhuān)門(mén)負責發(fā)送和接受消息。
WCF系列(一) -- 完全不使用配置文件構建和使用WCF服務(wù)
宿主
WCF典型的宿主包括以下四種:
l Self-Hosting 自托管宿主
l Managed Windows Services(Windows 服務(wù)宿主)
l Internet Information Services(IIS宿主)
l Windows Process Activation Service(WAS宿主)
1、自托管宿主利用
WCF提供的ServiceHost<T>提供的Open()和Close()方法,可以便于開(kāi)發(fā)者在控制臺應用程序,Windows應用程序乃至于ASP.NET應用程序中托管服務(wù)。不管自宿主的環(huán)境是何種應用程序,實(shí)質(zhì)上托管服務(wù)的方式都是一致的。例如在控制臺應用程序中:
using (ServiceHost host =
new ServiceHost(typeof(DocumentsExplorerService)))
{ host.Open();
Console.WriteLine("The Service had been launched.");
Console.Read();
}
由于ServiceHost實(shí)例是被創(chuàng )建在應用程序域中,因此我們必須保證宿主進(jìn)程在調用服務(wù)期間不會(huì )被關(guān)閉,因此我們利用Console.Read()來(lái)阻塞進(jìn)程,以使得控制臺應用程序能夠一直運行,直到認為地關(guān)閉應用程序。如果是Windows應用程序,則可以將創(chuàng )建ServiceHost實(shí)例的代碼放在主窗體的相關(guān)代碼中,保證服務(wù)宿主不會(huì )被關(guān)閉。相應地,我們需要配置應用程序的app.config配置文件:
<configuration>
<system.serviceModel>
<services>
<service name="DocumentsExplorerServiceImplementation.DocumentsExplorerService"
behaviorConfiguration="DocumentExplorerServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/DocumentExplorerService"/> </baseAddresses>
</host>
<endpoint address=""
binding="basicHttpBinding" bindingConfiguration="DocumentExplorerServiceBinding" contract="DocumentsExplorerServiceContract.IDocumentsExplorerService"/>
<endpoint address="mex"
binding="mexHttpBinding" contract="IMetadataExchange"/> </service>
</services>
<bindings>
<basicHttpBinding>
<binding name="DocumentExplorerServiceBinding"
sendTimeout="00:10:00" transferMode="Streamed"
messageEncoding="Text" textEncoding="utf-8" maxReceivedMessageSize="9223372036854775807"> </binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="DocumentExplorerServiceBehavior">
<serviceMetadata
httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
注意,配置文件中的服務(wù)名必須包含服務(wù)契約以及服務(wù)類(lèi)的命名空間。此外,在配置文件中我通過(guò)<baseAddresses>標簽為服務(wù)添加了基地址,因此在endpoint中,address為""。此時(shí),調用服務(wù)的客戶(hù)端配置文件也應與服務(wù)的配置保持一致:
注意,兩個(gè)配置文件中的服務(wù)地址都是一樣的,對于綁定的配置也基本一致。在通常的企業(yè)應用中,我們很少會(huì )采用自宿主方式托管服務(wù),這是因為這種方式必須要在應用程序運行下,客戶(hù)端才能夠調用服務(wù),且并不便于隨時(shí)啟動(dòng)和停止服務(wù)。除了不具有易用性與易管理性之外,在可靠性、性能等諸多方面受到很多限制。但由于它簡(jiǎn)單、易于實(shí)現,因而往往用于開(kāi)發(fā)期間的調試或演示環(huán)境。自托管宿主支持所有的綁定。
2、Windows Services宿主
Windows Services宿主則完全克服了自托管宿主的缺點(diǎn),它便于管理者方便地啟動(dòng)或停止服務(wù),且在服務(wù)出現故障之后,能夠重新啟動(dòng)服務(wù)。我們還可以通過(guò)Service Control Manager(服務(wù)控制管理器),將服務(wù)設置為自動(dòng)啟動(dòng)方式,省去了服務(wù)的管理工作。此外,Windows Services自身還提供了一定的安全性以及檢測機制和日志機制。
Windows Services宿主的實(shí)現也非常簡(jiǎn)單。我們可以在Visual Studio中創(chuàng )建Windows Services項目。在創(chuàng )建項目之后,就可以創(chuàng )建一個(gè)繼承了System.ServiceProcess.ServiceBase類(lèi)的Windows服務(wù)類(lèi)。Windows服務(wù)類(lèi)繼承了ServiceBase類(lèi)的OnStart()和OnStop()方法,完成Windows服務(wù)的啟動(dòng)與停止。我們可以重寫(xiě)這兩個(gè)方法,將ServiceHost的啟動(dòng)與關(guān)閉對應地放入這兩個(gè)方法的實(shí)現中。例如我們創(chuàng )建的DocumentsExplorerWindowsService類(lèi):
namespace BruceZhang.WCF.DocumentsExplorer
{
public partial class DocumentsExplorerWindowsService : ServiceBase
{
private ServiceHost m_serviceHost = null;
public static void Main()
{
ServiceBase.Run(new DocumentsExplorerWindowsService());
}
public DocumentsExplorerWindowsService()
{
InitializeComponent();
ServiceName = "DocumentsExplorerService";
}
protected override void OnStart(string[] args)
{
if (m_serviceHost != null)
{
m_serviceHost.Close();
}
m_serviceHost = new ServiceHost(typeof(DocumentsExplorerService));
m_serviceHost.Open();
}
protected override void OnStop()
{
if (m_serviceHost != null)
{
m_serviceHost.Close();
m_serviceHost = null;
}
}
}
}
在Main函數中,我們通過(guò)ServiceBase.Run()靜態(tài)方法創(chuàng )建Windows服務(wù)實(shí)例,并在Windows服務(wù)類(lèi)的構造函數中,調用ServiceBase類(lèi)的ServiceName屬性指定服務(wù)名。在重寫(xiě)的OnStart()方法中,我們首先判斷是否已經(jīng)存在ServiceHost實(shí)例,如果不存在,則創(chuàng )建它。創(chuàng )建ServiceHost實(shí)例的方法與自托管宿主方式相同。
為了完成ServiceHost實(shí)例的創(chuàng )建,我們同樣需要在項目中添加app.config配置文件,配置文件的內容與前完全一樣。
如果在企業(yè)應用中要使用WCF技術(shù),最佳的宿主方式我認為就是Windows Services,尤其是服務(wù)器的操作系統不是Vista的情況之下。它便于服務(wù)的管理,能夠維持服務(wù)長(cháng)時(shí)期的運行,同時(shí)它還支持所有的綁定,因而受到的限制最小。然而,這種方式唯一的缺點(diǎn)卻是對宿主的部署相對比較復雜,必須通過(guò).NET提供的Installutil.exe工具完成對服務(wù)宿主的安裝(也可以通過(guò)安裝包的自定義操作完成)。
若要完成對服務(wù)宿主的安裝,我們還需要創(chuàng )建它的安裝程序。我們可以自定義一個(gè)安裝類(lèi),使其繼承自System.Configuration.Install.Installer類(lèi)。更簡(jiǎn)單的辦法則是通過(guò)Windows服務(wù)提供的設計時(shí)支持,直接創(chuàng )建安裝類(lèi)。方法是在Windows服務(wù)例如DocumentsExplorerWindowsService的設計器視圖下,通過(guò)單擊右鍵,在快捷菜單中選擇“Add Installer”,如圖二所示:
圖二 添加安裝程序
創(chuàng )建的安裝程序ExplorerServiceInstaller如下所示:
namespace BruceZhang.WCF.DocumentsExplorer
{
//Type services.msc to access the Service Control Manager(SCM) and browse the windows services
//Type installutil /u filename to uninstall the windows service
[RunInstaller(true)]
public partial class ExplorerServiceInstaller : Installer
{
private ServiceProcessInstaller m_process;
private ServiceInstaller m_service;
public ExplorerServiceInstaller()
{
InitializeComponent();
m_process = new ServiceProcessInstaller();
m_process.Account = ServiceAccount.LocalSystem;
m_service = new ServiceInstaller();
m_service.ServiceName = "DocumentsExplorerService";
Installers.Add(m_process);
Installers.Add(m_service);
}
}
}
在ExplorerServiceInstaller類(lèi)中,ServiceAccount是一個(gè)枚舉類(lèi)型,可以設置為L(cháng)ocalService,LocalSystem,NetworkService以及User值。其中,LocalService的安全性最低,User值的安全性最高,需要有效的用戶(hù)賬號方才可以安裝服務(wù)。
對于安裝程序而言,也可以直接在設計器視圖下設置它的屬性。
安裝程序直接建立在Windows服務(wù)的程序集中,編譯之后會(huì )獲得一個(gè)exe文件,例如DocumentsExplorer.exe。然后,我們通過(guò)在Visual Studio的Command Prompt模式下運行如下命令:
installutil DocumentsExplorer.exe
即可完成對服務(wù)宿主的安裝。
打開(kāi)服務(wù)控制管理器(可以在Command Prompt模式下輸入Services.msc打開(kāi)),可以看到名為DocumentsExplorer

圖三 服務(wù)控制管理器
如果要卸載該服務(wù)宿主,可以通過(guò)installutil的/u開(kāi)關(guān)卸載。
在企業(yè)應用中,我們往往會(huì )將該Windows服務(wù)設置為自動(dòng)啟動(dòng),可以簡(jiǎn)化管理員的工作。
關(guān)于如何使用ServiceBase
http://msdn.microsoft.com/en-us/zt39148a(zh-cn,VS.80).aspx
3、IIS宿主(說(shuō)明,這里講的IIS為IIS 6.0)
若要使用IIS宿主,需要為程序集中添加一個(gè)svc文件。我們可以通過(guò)為項目添加一個(gè)新項的方式添加svc文件:
4、WAS宿主
WAS是IIS 7.0的一部分,但也可以獨立地安裝與配置。WAS支持所有可用的WCF傳輸協(xié)議、端口與隊列。
利用WAS托管服務(wù)與IIS宿主托管服務(wù)的方法并沒(méi)有太大的區別,仍然需要創(chuàng )建svc文件,同時(shí)在IIS中需要在站點(diǎn)中創(chuàng )建應有程序指向托管應用程序,還可以設置訪(fǎng)問(wèn)服務(wù)的別名與應用程序池。
由于WAS訴諸支持所有的綁定,因此此時(shí)的服務(wù)綁定并不會(huì )受到宿主的限制。
聯(lián)系客服