指定端點位址
所有 Windows Communication Foundation (WCF) 服務的通訊都會透過其端點進行。 每個 ServiceEndpoint 都包含有 Address、Binding 和 Contract。 合約會指定哪些為可用的作業。 繫結會指定如何與服務通訊,而位址則指定何處可找到服務。 每個端點必須具備唯一的位址。 端點位址是由 EndpointAddress 類別所代表,其中包含代表服務位址的統一資源識別元 (URI)、代表服務之安全性身分識別的 Identity,以及選用的 Headers 集合。 選用標頭會提供更多詳細的定址資訊來識別端點或與端點互動。 例如,標頭會指出如何處理傳入訊息、端點應該將回覆訊息傳送到哪裡,或是當有多個執行個體可用時,要使用哪個服務執行個體來處理來自特定使用者的傳入訊息。
端點位址的定義
在 WCF 中,EndpointAddress 會依據 WS-Addressing 標準的定義,製造端點參考 (EPR) 的模型。
大部分傳輸的位址 URI 具有四個部分。 例如,"http://www.fabrikam.com:322/mathservice.svc/secureEndpoint" 這個 URI 便具有下列四個部分:
配置:http:
電腦:www.fabrikam.com
(選擇性) 連接埠:322
路徑:/mathservice.svc/secureEndpoint
EPR 模型的一部分,就是每個端點參考都包含可新增額外識別資訊的某些參考參數。 在 WCF 中,這些參考參數會模型化為 AddressHeader 類別的執行個體。
您可以強制使用程式碼,或是透過組態以宣告的形式來指定服務的端點位址。 在程式碼中定義端點通常不太實用,因為部署之服務的繫結和位址通常與開發服務時所使用的繫結和位址不同。 一般來說,透過組態來定義服務端點會比透過程式碼來得實際一些。 將繫結和位址資訊留在程式碼外面可讓它們直接進行變更,而不需要重新編譯或重新部署應用程式。 如果在程式碼或組態中沒有指定端點,則執行階段會針對服務所實作的每個合約,在每個基底位址上加入一個預設端點。
在 WCF 中,有兩種方式可以用來指定服務的端點位址。 您可以為每個與服務相關聯的端點指定絕對位址,或是為服務的 ServiceHost 提供基底位址,然後指定相對於此基底位址所定義之服務相關聯的每個端點位址。 您可以透過組態或程式碼,使用這些程序中的任何一個來指定服務的端點位址。 如果您沒有指定相對位址,則服務會使用基底位址。 您可以讓同一個服務使用多個基底位址,但是每個服務只允許每個傳輸使用一個基底位址。 如果您具有多個端點,而其中每一個都設定為不同的繫結,則其位址必須是唯一的。 使用相同繫結但不同合約的端點可以使用相同的位址。
使用 IIS 裝載時,您不用自行管理 ServiceHost 執行個體。 裝載於 IIS 時,基底位址一律是服務的 .svc 檔案中指定的位址。 因此請務必針對 IIS 裝載的服務端點使用相對端點位址。 在部署服務時,提供完整的端點位址可能會導致錯誤。 如需詳細資訊,請參閱 部署已裝載網際網路資訊服務的 WCF 服務.
在組態中定義端點位址
若要在組態檔中定義端點,請使用 <endpoint> 項目。
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello"/>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
呼叫 Open 方法時 (亦即,當裝載的應用程式嘗試啟動服務時),系統會尋找 <service> 項目 (內含指定 "UE.Samples.HelloService" 的名稱屬性)。 如果找到了 <service> 項目,則系統會載入指定的類別,並使用組態檔提供的端點定義來建立端點。 這項機制可讓您透過兩行程式碼輕鬆地載入並啟動服務,同時不用在程式碼中留下繫結與位址資訊。 使用這種方法的好處是,您不用重新編譯或重新部署應用程式,便可進行這些變更。
選用的標頭會在 <headers> element中宣告。 下列是用來指定組態檔中服務端點的項目範例,此指定組態檔會區分以下兩個標頭的不同:來自 http://tempuri1.org/ 的 "Gold" 用戶端和來自 http://tempuri2.org/ 的 "Standard" 用戶端。 呼叫此服務的用戶端必須在其組態檔中具備適當的 <headers> element。
<configuration>
<system.serviceModel>
<services>
<service name="UE.Samples.HelloService"
behaviorConfiguration="HelloServiceBehavior">
<endpoint address="/Address1"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri1.org/">Gold</Member>
</headers>
</endpoint>
<endpoint address="/Address2"
binding="basicHttpBinding"
contract="UE.Samples.IHello">
<headers>
<Member xmlns="http://tempuri2.org/">Silver</Member>
</headers>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HelloServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
如先前所示,您也可以在個別訊息上設定標頭,而不是在某個端點的所有訊息上設定標頭。 如下列範例所示,您可以使用 OperationContextScope 在用戶端應用程式上建立新的內容,將自訂標頭新增至傳出的訊息,以完成這項工作。
Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
Using scope As New OperationContextScope(wcfClient.InnerChannel)
Dim header As MessageHeader = MessageHeader.CreateHeader("Service-Bound-CustomHeader", _
"http://Microsoft.WCF.Documentation", "Custom Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' Making calls.
Console.WriteLine("Enter the greeting to send: ")
Dim greeting As String = Console.ReadLine()
'Console.ReadLine();
header = MessageHeader.CreateHeader("Service-Bound-OneWayHeader", _
"http://Microsoft.WCF.Documentation", "Different Happy Value.")
OperationContext.Current.OutgoingMessageHeaders.Add(header)
' One-way
wcfClient.Push(greeting)
Me.wait.WaitOne()
' Done with service.
wcfClient.Close()
Console.WriteLine("Done!")
Console.ReadLine()
End Using
Catch timeProblem As TimeoutException
Console.WriteLine("The service operation timed out. " & timeProblem.Message)
Console.ReadLine()
wcfClient.Abort()
Catch commProblem As CommunicationException
Console.WriteLine("There was a communication problem. " & commProblem.Message)
Console.ReadLine()
wcfClient.Abort()
End Try
SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
{
MessageHeader header
= MessageHeader.CreateHeader(
"Service-Bound-CustomHeader",
"http://Microsoft.WCF.Documentation",
"Custom Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// Making calls.
Console.WriteLine("Enter the greeting to send: ");
string greeting = Console.ReadLine();
//Console.ReadLine();
header = MessageHeader.CreateHeader(
"Service-Bound-OneWayHeader",
"http://Microsoft.WCF.Documentation",
"Different Happy Value."
);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// One-way
wcfClient.Push(greeting);
this.wait.WaitOne();
// Done with service.
wcfClient.Close();
Console.WriteLine("Done!");
Console.ReadLine();
}
}
catch (TimeoutException timeProblem)
{
Console.WriteLine("The service operation timed out. " + timeProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
Console.WriteLine("There was a communication problem. " + commProblem.Message);
Console.ReadLine();
wcfClient.Abort();
}
中繼資料中的端點位址
在 Web 服務描述語言 (WSDL) 中,端點位址會表示為對應端點的 wsdl:port 項目中之 WS-Addressing EndpointReference (EPR) 項目。 EPR 包含端點的位址以及任何位址屬性。 請注意,wsdl:port 內的 EPR 會取代 soap:Address,如下列範例所示。
在程式碼中定義端點位址
您可以使用 EndpointAddress 類別,在程式碼中建立端點位址。 您可以為端點位址指定完整路徑的 URI,或是相對於服務基底位址的路徑 URI。 下列程式碼說明如何建立 EndpointAddress 類別的執行個體,並將其新增至裝載服務的 ServiceHost 執行個體。
下列範例示範如何在程式碼中指定完整端點位址。
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
string address = "https://localhost:8000/HelloService/MyService";
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), address);
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
下列範例示範如何將相對位址 ("MyService") 新增至服務主機的基底位址。
Uri baseAddress = new Uri("https://localhost:8000/HelloService");
using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), "MyService");
serviceHost.Open();
Console.WriteLine("Press <enter> to terminate service");
Console.ReadLine();
serviceHost.Close();
}
注意: |
---|
在服務應用程式中 ServiceDescription 的屬性,絕對不能在呼叫 ServiceHostBase 上的 OnOpening 方法之後遭到修改。 如果在通過該點之後修改一些成員,像是 Credentials 屬性及 ServiceHostBase 與 ServiceHost 上的 AddServiceEndpoint 方法,便會擲回例外狀況。 其他成員可讓您加以修改,但結果仍未定義。 同樣地,您不可以在呼叫 ChannelFactory 上的 OnOpening 之後修改用戶端上的 ServiceEndpoint 值。 Credentials 屬性如果在通過該點之後修改,便會擲回例外狀況。 其他的用戶端說明值可以修改且不會造成錯誤,但是結果仍未定義。 無論在是服務或是用戶端,我們的建議做法是在呼叫 Open 之前先修改此描述。 |
使用預設端點
如果在程式碼或組態中沒有指定端點,則執行階段會針對服務所實作的每個服務合約,在每個基底位址上加入一個預設端點,藉以提供預設端點。 基底位址可以在程式碼或組態中指定,而預設端點則會在 ServiceHost 上呼叫 Open 時加入。
如果沒有明確提供端點,在呼叫 Open 之前,仍可藉由在 ServiceHost 上呼叫 AddDefaultEndpoints 來加入預設端點。如需詳細資訊預設端點、繫結與行為的詳細資訊,請參閱 簡化的組態 及 WCF 服務的簡化組態。