指定端點位址
與 Windows Communication Foundation (WCF) 服務進行的所有通訊,需透過端點來完成。 每個 ServiceEndpoint 都包含有 Address、Binding 和 Contract。 合約會指定哪些為可用的作業。 繫結會指定如何與服務通訊,而位址則指定何處可找到服務。 每個端點必須具備唯一的位址。 端點位址是由 EndpointAddress 類別所代表,其中包含代表服務位址的統一資源識別元 (URI)、代表服務之安全性身分識別的 Identity,以及選用的 Headers 集合。 選用標頭會提供更多詳細的定址資訊來識別端點或與端點互動。 例如,標頭會指出如何處理傳入訊息、端點應該將回覆訊息傳送到哪裡,或是當有多個執行個體可用時,要使用哪個服務執行個體來處理來自特定使用者的傳入訊息。
端點位址的定義
在 WCF 中,EndpointAddress 會按照 WS-Addressing 標準的定義,建立端點參考 (EPR) 的模型。
大部分傳輸的位址 URI 具有四個部分。 例如,URI http://www.fabrikam.com:322/mathservice.svc/secureEndpoint
包含下列四個部分:
配置:http:
機器:
www.fabrikam.com
(選擇性) 連接埠:322
路徑:/mathservice.svc/secureEndpoint
EPR 模型的一部分,就是每個端點參考都包含可新增額外識別資訊的某些參考參數。 在 WCF 中,這些參考參數會經由建模成為 AddressHeader 類別的執行個體。
您可以強制使用程式碼,或是透過組態以宣告的形式來指定服務的端點位址。 在程式碼中定義端點通常不太實用,因為部署之服務的繫結和位址通常與開發服務時所使用的繫結和位址不同。 一般來說,透過組態來定義服務端點會比透過程式碼來得實際一些。 將繫結和位址資訊留在程式碼外面可讓它們直接進行變更,而不需要重新編譯或重新部署應用程式。 如果在程式碼或組態中沒有指定端點,則執行階段會針對服務所實作的每個合約,在每個基底位址上加入一個預設端點。
在 WCF 中為服務指定端點位址的方法有兩種。 您可以為每個與服務相關聯的端點指定絕對位址,或是為服務的 ServiceHost 提供基底位址,然後指定相對於此基底位址所定義之服務相關聯的每個端點位址。 您可以透過組態或程式碼,使用這些程序中的任何一個來指定服務的端點位址。 如果您沒有指定相對位址,則服務會使用基底位址。 您可以讓同一個服務使用多個基底位址,但是每個服務只允許每個傳輸使用一個基底位址。 如果您具有多個端點,而其中每一個都設定為不同的繫結,則其位址必須是唯一的。 使用相同繫結但不同合約的端點可以使用相同的位址。
使用 IIS 裝載時,您不用自行管理 ServiceHost 執行個體。 裝載於 IIS 時,基底位址一律是服務的 .svc 檔案中指定的位址。 因此請務必針對 IIS 裝載的服務端點使用相對端點位址。 在部署服務時,提供完整的端點位址可能會導致錯誤。 如需詳細資訊,請參閱部署 Internet Information Services 裝載的 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」會宣告選擇性的標頭。<> 以下範例中,在組態檔中用於指定服務端點的元素,區分成兩種標頭:來自 http://tempuri1.org/
的「Gold」用戶端,以及來自 http://tempuri2.org/
的「Standard」用戶端。 用戶端呼叫此服務時,組態檔必須擁有對應的「headers」。<>
<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 在用戶端應用程式上建立新的內容,將自訂標頭新增至傳出的訊息,以完成這項工作。
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();
}
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
中繼資料中的端點位址
在 Web 服務描述語言 (WSDL) 中,端點位址會表示為對應端點的 EndpointReference
項目中之 WS-Addressing wsdl:port
(EPR) 項目。 EPR 包含端點的位址以及任何位址屬性。 請注意,wsdl:port
內的 EPR 會取代 soap:Address
,如下列範例所示。
在程式碼中定義端點位址
您可以使用 EndpointAddress 類別,在程式碼中建立端點位址。 您可以為端點位址指定完整路徑的 URI,或是相對於服務基底位址的路徑 URI。 下列程式碼說明如何建立 EndpointAddress 類別的執行個體,並將其新增至裝載服務的 ServiceHost 執行個體。
下列範例示範如何在程式碼中指定完整端點位址。
Uri baseAddress = new Uri("http://localhost:8000/HelloService");
string address = "http://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("http://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 的屬性,絕對不能在呼叫 OnOpening 上的 ServiceHostBase 方法之後遭到修改。 如果在通過該點之後修改一些成員,像是 Credentials 屬性及 AddServiceEndpoint
與 ServiceHostBase 上的 ServiceHost 方法,便會擲回例外狀況。 其他成員可讓您加以修改,但結果仍未定義。
同樣地,您不可以在呼叫 ServiceEndpoint 上的 OnOpening 之後修改用戶端上的 ChannelFactory 值。 Credentials 屬性如果在通過該點之後修改,便會擲回例外狀況。 其他的用戶端說明值可以修改而不會造成錯誤,但是結果仍為未定義。
無論是在服務或是用戶端,建議的做法都是在呼叫 Open 之前修改說明。
使用預設端點
如果在程式碼或組態中沒有指定端點,則執行階段會針對服務所實作的每個服務合約,在每個基底位址上加入一個預設端點,藉以提供預設端點。 基底位址可以在程式碼或組態中指定,而預設端點則會在 Open 上呼叫 ServiceHost 時加入。
如果沒有明確提供端點,在呼叫 AddDefaultEndpoints 之前,仍可藉由在 ServiceHost 上呼叫 Open 來加入預設端點。 如需預設端點、繫結和行為的詳細資訊,請參閱簡化的組態和 WCF 服務的簡化組態。