Windows Communication Foundation 體系結(jié)構(gòu)概述發(fā)布日期: 2006-5-15 | 更新日期: 2006-5-15
摘要:概覽 Windows Communication Foundation (WCF) 體系結(jié)構(gòu)及其主要概念。代碼示例演示 WCF 約定、終結(jié)點(diǎn)和行為。 本頁內(nèi)容
簡介本文檔提供 Windows Communication Foundation (WCF) 體系結(jié)構(gòu)的概覽。本文旨在闡釋 WCF 中的主要概念以及它們?nèi)绾螀f(xié)調(diào)工作。還有幾個代碼示例對這些概念進(jìn)行深入闡釋,但代碼不是本文檔的重點(diǎn)。 本文檔下面的部分分為以下兩個主要內(nèi)容:
WCF 基礎(chǔ)WCF 服務(wù)是一個公開終結(jié)點(diǎn) 集合的程序。每個終結(jié)點(diǎn)都是一個與外界通訊的入口。 客戶端是一個與一個或多個終結(jié)點(diǎn)交換消息的程序??蛻舳诉€可以公開一個終結(jié)點(diǎn),從而以雙工消息交換的模式從服務(wù)接收消息。 以下部分更詳細(xì)地描述了這些基礎(chǔ)。 終結(jié)點(diǎn) 一個服務(wù)終結(jié)點(diǎn)具有一個地址、一個綁定 和一個約定。 終結(jié)點(diǎn)的地址是終結(jié)點(diǎn)駐留的網(wǎng)絡(luò)地址。EndpointAddress 類表示一個 WCF 終結(jié)點(diǎn)地址。 終結(jié)點(diǎn)的綁定指定終結(jié)點(diǎn)與外界通訊的方式,包括傳輸協(xié)議(例如,TCP、HTTP)、編碼(例如,文本、二進(jìn)制文件)以及安全要求(例如,SSL、SOAP 消息安全)等。Binding 類表示 WCF 綁定。 終結(jié)點(diǎn)的約定指定終結(jié)點(diǎn)通訊的內(nèi)容,它本質(zhì)上是操作中有組織的消息集合,這些操作具有基本的消息交換模式 (MEPs),如單工、雙工,以及請求/應(yīng)答。ContractDescription 類表示 WCF 約定。 ServiceEndpoint 類表示終結(jié)點(diǎn),它具有一個 EndpointAddress、一個綁定以及一個 ContractDescription,分別對應(yīng)于終結(jié)點(diǎn)的地址、綁定和約定(參見圖 1)。 ![]() 圖 1. 每個服務(wù)的終結(jié)點(diǎn)包含一個 EndpointAddress、一個綁定以及一個由 ContractDescription 表示的約定。 EndpointAddress EndpointAddress 實(shí)際上是一個 URI、一個標(biāo)識和一個可選標(biāo)頭的集合,如圖 2 所示。 終結(jié)點(diǎn)的安全標(biāo)識通常就是它的 URI;然而在高級方案中,可以使用 Identity 地址屬性獨(dú)立于 URI 來顯式設(shè)置標(biāo)識。 可選標(biāo)頭用于提供除終結(jié)點(diǎn) URI 外的其他尋址信息。例如,地址標(biāo)頭對于區(qū)分共享相同地址 URI 的多個終結(jié)點(diǎn)很有用。 ![]() 圖 2. EndpointAddress 包含一個 URI,AddressProperties 包含一個標(biāo)識和一個 AddressHeaders 集合。 綁定 綁定具有名稱、命名空間,以及一個可編寫的綁定元素的集合(圖 3)。綁定的名稱和命名空間在服務(wù)的元數(shù)據(jù)中唯一標(biāo)識該綁定。每個綁定元素都描述終結(jié)點(diǎn)與外界通訊的方式 的一個方面。 ![]() 圖 3. 綁定類及其成員 例如,圖 4 顯示一個包含三個綁定元素的綁定元素集合。每個綁定元素的存在都描述與終結(jié)點(diǎn)通訊的方式 的一部分。TcpTransportBindingElement 表示終結(jié)點(diǎn)將使用 TCP 作為傳輸協(xié)議與外界通訊。ReliableSessionBindingElement 表示終結(jié)點(diǎn)使用可靠的消息處理來提供消息傳遞保證。SecurityBindingElement 表示終結(jié)點(diǎn)使用 SOAP 消息安全性。每個綁定元素通常具有這樣的屬性:它們進(jìn)一步描述與終結(jié)點(diǎn)通訊的方式 的細(xì)節(jié)。例如,ReliableSessionBindingElement 有一個 Assurances 屬性,它指定所需的郵件傳遞保證,如無,至少一次,至多一次,或正好一次。 ![]() 圖 4. 一個具有三個綁定元素的綁定示例 綁定中綁定元素的順序和類型十分重要:綁定元素的集合用于構(gòu)建根據(jù)其中綁定元素的順序排序的通訊堆棧。最后一個添加到集合中的綁定元素對應(yīng)于通訊堆棧的底部元素,而第一個綁定元素對應(yīng)于頂部元素。傳入消息自下向上流經(jīng)堆棧,而傳出消息自上向下流經(jīng)堆棧。因此,集合中綁定元素的順序直接影響通訊堆棧組件處理消息的順序。請注意,WCF 提供一組預(yù)定義的綁定,在大多數(shù)方案中可以使用這些綁定而不用定義自定義綁定。 約定 WCF 約定是一個操作的集合,這些操作指定終結(jié)點(diǎn)與外界通訊的內(nèi)容。每個操作都是一個簡單的消息交換,例如單向或請求/應(yīng)答消息交換。 ContractDescription 類用于描述 WCF 約定及其操作。在 ContractDescription 中,每個 Contract 操作都有一個對應(yīng)的 OperationDescription,它們描述操作的各個方面,如操作是單向還是請求/應(yīng)答。每個 OperationDescription 還使用一個 MessageDescriptions 集合描述組成操作的各個消息。 利用 WCF 編程模型,ContractDescription 通常從定義約定的接口或類進(jìn)行創(chuàng)建。該類型使用 ServiceContractAttribute 進(jìn)行注釋,其對應(yīng)于終結(jié)點(diǎn)操作的方法使用OperationContractAttribute 進(jìn)行注釋。您也可以手動構(gòu)建一個 ContractDescription,無需從使用屬性注釋的 CLR 類型開始。 一個雙工 約定定義兩組邏輯操作:一組操作是,服務(wù)向客戶端公開以進(jìn)行調(diào)用;另一組操作是,客戶端向服務(wù)公開以進(jìn)行調(diào)用。用于定義雙工約定的程序模型會將每組操作分為一個單獨(dú)的類型(每種類型必須是一個類或一個接口),并使用 ServiceContractAttribute 注釋表示服務(wù)操作的約定,引用定義客戶端(或回調(diào))操作的約定。此外,ContractDescription 還包含對每種類型的引用,從而可以將其組成一個雙工約定。 與綁定類似,每個約定都有一個在服務(wù)元數(shù)據(jù)中唯一標(biāo)識該約定的名稱和命名空間。 每個約定還有一個 ContractBehaviors 集合,它是修改或擴(kuò)展約定行為的模塊。下一部分對這些行為進(jìn)行更詳細(xì)的說明。 ![]() 圖 5. ContractDescription 類描述 WCF 約定 行為 行為是修改或擴(kuò)展服務(wù)或客戶端功能的類型。例如,ServiceMetadataBehavior 實(shí)現(xiàn)的元數(shù)據(jù)行為控制服務(wù)是否發(fā)布元數(shù)據(jù)。同樣,安全行為控制模擬和授權(quán),而事務(wù)行為控制登記和自動完成事務(wù)。 行為還參與構(gòu)建信道的過程,它可以根據(jù)用戶指定的設(shè)置和/或服務(wù)或信道的其他方面修改該信道。 服務(wù)行為是實(shí)現(xiàn) IServiceBehavior 并將其應(yīng)用于服務(wù)的類型。同樣,信道行為是實(shí)現(xiàn) IChannelBehavior 并將其應(yīng)用于客戶端信道的類型。 服務(wù)和信道描述 ServiceDescription 類是一個內(nèi)存內(nèi)結(jié)構(gòu),它描述一個 WCF 服務(wù),包括服務(wù)公開的終結(jié)點(diǎn)、應(yīng)用于服務(wù)的行為,以及實(shí)現(xiàn)該服務(wù)的類型(一個類)(參見圖 6)。ServiceDescription 用于創(chuàng)建元數(shù)據(jù)、代碼/配置和信道。 您可以手動構(gòu)建該 ServiceDescription 對象。您也可以從使用特定 WCF 屬性注釋的類型創(chuàng)建它,這是較為常見的情況。該類型的代碼可以手動編寫,也可以使用 WCF 工具(名為 svcutil.exe)從 WSDL 文檔生成。 盡管 ServiceDescription 對象可以顯式創(chuàng)建并填充,但它們通常作為運(yùn)行服務(wù)的一部分在后臺創(chuàng)建。 ![]() 圖 6. ServiceDescription 對象模型 在客戶端同樣如此,ChannelDescription 描述一個到特定終結(jié)點(diǎn)的 WCF 客戶端信道(圖 7)。ChannelDescription 類有一個 IchannelBehaviors 的集合,IchannelBehaviors 是應(yīng)用于信道的行為。它還有一個描述終結(jié)點(diǎn)(信道與該終結(jié)點(diǎn)進(jìn)行通訊)的 ServiceEndpoint。 請注意,與 ServiceDescription 不同,ChannelDescription 只包含一個代表目標(biāo)終結(jié)點(diǎn)(信道與該終結(jié)點(diǎn)進(jìn)行通訊)的 ServiceEndpoint。 ![]() 圖 7. ChannelDescription 對象模型 WCF 運(yùn)行時 WCF 運(yùn)行時是一組負(fù)責(zé)發(fā)送和接收消息的對象。例如,格式化消息、應(yīng)用安全性、使用各種傳輸協(xié)議傳輸和接收消息,以及向適當(dāng)?shù)牟僮鞣职l(fā)接收到的消息,所有這些操作都在 WCF 運(yùn)行時中發(fā)生。以下部分闡釋 WCF 運(yùn)行時的主要概念。 消息 WCF 消息是客戶端和終結(jié)點(diǎn)之間的數(shù)據(jù)交換單元。消息本質(zhì)上是 SOAP 消息 InfoSet 的一個內(nèi)存內(nèi)表示形式。請注意,消息不與文本 XML 綁定在一起。另外,根據(jù)所使用的編碼機(jī)制,消息可以使用 WCF 二進(jìn)制格式、文本 XML 或任何其他自定義格式序列化。 信道 信道是將消息發(fā)送至終結(jié)點(diǎn)和從終結(jié)點(diǎn)接收消息的核心抽象。從廣義上講,有兩類信道:傳輸信道使用某種形式的傳輸協(xié)議(如 TCP、UDP 或 MSMQ)處理發(fā)送或接收不透明的八位字節(jié)流。另一方面,協(xié)議信道通過處理并有可能修改消息實(shí)現(xiàn)基于 SOAP 的協(xié)議。例如,安全信道添加并處理 SOAP 消息頭,并且可能通過對其進(jìn)行加密修改消息體。信道是可編輯的,因此一層信道可以位于另一層信道之上,而另一層信道又可以位于第三層信道之上。 EndpointListener EndpointListener 是與 ServiceEndpoint 等效的運(yùn)行時。ServiceEndpoint 的 EndpointAddress、約定和綁定(代表位置、內(nèi)容 和方式)分別對應(yīng)于 EndpointListener 的偵聽地址、消息篩選和分發(fā),以及信道堆棧。EndpointListener 包含負(fù)責(zé)發(fā)送和接收消息的信道堆棧。 ServiceHost 和 ChannelFactory WCF 服務(wù)運(yùn)行時通常通過調(diào)用 ServiceHost.Open 在后臺創(chuàng)建。ServiceHost(如圖 6 所示)驅(qū)動從服務(wù)類型創(chuàng)建 ServiceDescription,并使用配置和/或代碼中定義的終結(jié)點(diǎn)填充 ServiceDescription 的 ServiceEndpoint 集合。然后,ServiceHost 使用 ServiceDescription 為 ServiceDescription 中的每個 ServiceEndpoint 以 EndpointListener 對象的形式創(chuàng)建一個信道堆棧。 ![]() 圖 8. ServiceHost 對象模型 同樣,在客戶端,客戶端運(yùn)行時由 ChannelFactory 創(chuàng)建,后者等效于客戶端的 ServiceHost。 ChannelFactory 驅(qū)動根據(jù)約定的類型、綁定以及 EndpointAddress 創(chuàng)建一個 ChannelDescription。然后,它使用該 ChannelDescription 客戶端的信道堆棧。 與服務(wù)運(yùn)行時不同,客戶端運(yùn)行時不包括含 EndpointListener,因?yàn)榭蛻舳耸冀K啟動到服務(wù)的連接,這樣就無需"偵聽"傳入的連接。 代碼示例本部分提供的代碼示例說明如何構(gòu)建服務(wù)和客戶端。這些示例旨在使上述概念更加具體化,而不是教您 WCF 編程。 定義并實(shí)現(xiàn)約定 如前所述,定義約定最簡單的方法是創(chuàng)建一個接口或類,并使用 ServiceContractAttribute 對其加以注釋,使系統(tǒng)能夠通過它輕松地創(chuàng)建一個 ContractDescription。 使用接口或類定義約定時,作為約定成員的每個接口或類方法都必須使用 OperationContractAttribute 進(jìn)行注釋。例如: using System.ServiceModel;
//a WCF contract defined using an interface
[ServiceContract]
public interface IMath
{
[OperationContract]
int Add(int x, int y);
}
在本例中,實(shí)現(xiàn)約定僅僅是創(chuàng)建一個實(shí)現(xiàn) IMath 的類。該類成為 WCF 服務(wù)類。例如: //the service class implements the interface
public class MathService : IMath
{
public int Add(int x, int y)
{ return x + y; }
}
定義終結(jié)點(diǎn)并啟動服務(wù) 終結(jié)點(diǎn)可在代碼或配置中進(jìn)行定義。在下面的示例中,DefineEndpointImperatively 方法顯示在代碼中定義終結(jié)點(diǎn)并啟動服務(wù)的最簡單方法。 DefineEndpointInConfig 方法顯示在配置中定義的等效終結(jié)點(diǎn)(配置示例在以下代碼之后)。 public class WCFServiceApp
{
public void DefineEndpointImperatively()
{
//create a service host for MathService
ServiceHost sh = new ServiceHost(typeof(MathService));
//use the AddEndpoint helper method to
//create the ServiceEndpoint and add it
//to the ServiceDescription
sh.AddServiceEndpoint(
typeof(IMath), //contract type
new WSHttpBinding(), //one of the built-in bindings
"http://localhost/MathService/Ep1"); //the endpoint‘s address
//create and open the service runtime
sh.Open();
}
public void DefineEndpointInConfig()
{
//create a service host for MathService
ServiceHost sh = new ServiceHost (typeof(MathService));
//create and open the service runtime
sh.Open();
}
}
<!-- configuration file used by above code -->
<configuration
xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<!-- service element references the service type -->
<service type="MathService">
<!-- endpoint element defines the ABC‘s of the endpoint -->
<endpoint
address="http://localhost/MathService/Ep1"
binding="wsHttpBinding"
contract="IMath"/>
</service>
</services>
</system.serviceModel>
</configuration>
向終結(jié)點(diǎn)發(fā)送消息 以下代碼顯示向 IMath 終結(jié)點(diǎn)發(fā)送消息的兩種方法。SendMessageToEndpoint 隱藏信道的創(chuàng)建,這在后臺發(fā)生,而 SendMessageToEndpointUsingChannel 示例顯式進(jìn)行信道的創(chuàng)建。 SendMessageToEndpoint 中的第一個示例使用一個名為 svcutil.exe 的工具以及服務(wù)的元數(shù)據(jù)來生成一個約定(本示例中的 IMath)、一個實(shí)現(xiàn)該約定的代理類(本示例中的 MathProxy),以及相關(guān)聯(lián)的配置(此處未顯示)。再次強(qiáng)調(diào),IMath 定義的約定指定了內(nèi)容(即可以執(zhí)行的操作),而生成的配置包含一個綁定(方式)和一個地址(位置)。 使用該代理類只需對其進(jìn)行實(shí)例化并調(diào)用 Add 方法。在后臺,該代理類將創(chuàng)建一個信道,并使用該信道與終結(jié)點(diǎn)通訊。 下面的 SendMessageToEndpointsUsingChannel 中的第二個示例顯示如何使用 ChannelFactory 與終結(jié)點(diǎn)直接通訊。在該示例中,使用 ChannelFactory.CreateChannel 直接創(chuàng)建信道,而不是用代理類或配置。而且,ChannelFactory 構(gòu)造函數(shù)采用這兩部分信息作為參數(shù),而不是使用配置來定義終結(jié)點(diǎn)的地址和綁定。定義一個終結(jié)點(diǎn)所需的第三部分信息(即約定)作為類型 T 傳入。 using System.ServiceModel;
//this contract is generated by svcutil.exe
//from the service‘s metadata
public interface IMath
{
[OperationContract]
public int Add(int x, int y)
{ return x + y; }
}
//this class is generated by svcutil.exe
//from the service‘s metadata
//generated config is not shown here
public class MathProxy : IMath
{
...
}
public class WCFClientApp
{
public void SendMessageToEndpoint()
{
//this uses a proxy class that was
//created by svcutil.exe from the service‘s metadata
MathProxy proxy = new MathProxy();
int result = proxy.Add(35, 7);
}
public void SendMessageToEndpointUsingChannel()
{
//this uses ChannelFactory to create the channel
//you must specify the address, the binding and
//the contract type (IMath)
ChannelFactory factory=new ChannelFactory(
new WSHttpBinding(),
new EndpointAddress("http://localhost/MathService/Ep1"));
IMath channel=factory.CreateChannel();
int result=channel.Add(35,7);
factory.Close();
}
}
定義自定義行為 定義自定義行為只需實(shí)現(xiàn) IServiceBehavior(或客戶端行為的 IChannelBehavior)。以下代碼顯示一個實(shí)現(xiàn) IServiceBehavior 的示例行為。在 IServiceBehavior.ApplyBehavior 中,代碼檢查 ServiceDescription 并寫出每個 ServiceEndpoint 的地址、綁定和約定,以及 ServiceDescription 中每個行為的名稱。 這個特殊的行為也是一個屬性(從 System.Attribute 繼承),使其可以以聲明方式應(yīng)用,如下所示。然而,行為不必成為屬性。 [AttributeUsageAttribute(
AttributeTargets.Class,
AllowMultiple=false,
Inherited=false)]
public class InspectorBehavior : System.Attribute,
System.ServiceModel.IServiceBehavior
{
public void ApplyBehavior(
ServiceDescription description,
Collection behaviors)
{
Console.WriteLine("-------- Endpoints ---------");
foreach (ServiceEndpoint endpoint in description.Endpoints)
{
Console.WriteLine("--> Endpoint");
Console.WriteLine("Endpoint Address: {0}",
endpoint.Address);
Console.WriteLine("Endpoint Binding: {0}",
endpoint.Binding.GetType().Name);
Console.WriteLine("Endpoint Contract: {0}",
endpoint.Contract.ContractType.Name);
Console.WriteLine();
}
Console.WriteLine("-------- Service Behaviors --------");
foreach (IServiceBehavior behavior in description.Behaviors)
{
Console.WriteLine("--> Behavior");
Console.WriteLine("Behavior: {0}", behavior.GetType().Name);
Console.WriteLine();
}
}
}
應(yīng)用自定義行為 通過向 ServiceDescription(或客戶端上的 ChannelDescription)添加行為的實(shí)例,所有行為都可以以命令方式應(yīng)用。例如,要以命令方式應(yīng)用 InspectorBehavior,您可以編寫以下代碼: ServiceHost sh = new ServiceHost(typeof(MathService)); sh.AddServiceEndpoint( typeof(IMath), new WSHttpBinding(), "http://localhost/MathService/Ep1"); //Add the behavior imperatively InspectorBehavior behavior = new InspectorBehavior(); sh.Description.Behaviors.Add(behavior); sh.Open(); 此外,從 System.Attribute 繼承的行為還能夠以聲明方式應(yīng)用于服務(wù)。例如,因?yàn)?InspectorBehavior 繼承自 System.Attribute,所以它可以以聲明方式得以應(yīng)用,如下所示: [InspectorBehavior]
public class MathService : IMath
{
public int Add(int x, int y)
{ return x + y; }
}
小結(jié)WCF 服務(wù)公開了一個終結(jié)點(diǎn)集合,其中每個終結(jié)點(diǎn)都是與外界通訊的入口。每個終結(jié)點(diǎn)都有一個地址、一個綁定和一個約定 (ABC)。地址是終結(jié)點(diǎn)駐留的位置,綁定是終結(jié)點(diǎn)通訊的方式,約定是終結(jié)點(diǎn)通訊的內(nèi)容。 在服務(wù)端,ServiceDescription 保存 ServiceEndpoint 的集合,其中每個 ServiceEndpoint 都描述服務(wù)公開的一個終結(jié)點(diǎn)。根據(jù)該描述,ServiceHost 創(chuàng)建一個運(yùn)行時,它針對 ServiceDescription 中的每個 ServiceEndpoint 包含了一個 EndpointListener。終結(jié)點(diǎn)的地址、綁定和約定(代表位置、內(nèi)容 和方式)分別對應(yīng)于 EndpointListener 的偵聽地址、消息篩選和分發(fā),以及信道堆棧。 同樣,在客戶端,ChannelDescription 保存與客戶端通訊的一個 ServiceEndpoint。根據(jù)該 ChannelDescription,ChannelFactory 創(chuàng)建可以與服務(wù)的終結(jié)點(diǎn)通訊的信道堆棧。 |
|
|