在WCF中有幾種涉及到地址的概念:基地址與相對位址、邏輯地址與物理地址。本文就從
WebService定址開始,總結一下WCF中的幾種地址。
目錄:
- WebService定址
- 邏輯地址與物理地址
- 基地址、相對位址、絕對位址
1、WebService定址與以協議無關的SOAP作為訊息的載體在被用戶端發往服務端以後就不再由用戶端所控制了。
如果以HTTP將SOAP從用戶端發往服務端,通過HTTP協議的標準動作如Get、Post進行操作,
服務處理完畢以後再通過HTTP響應發往用戶端這樣一次互動就完成了。可事實上,SOAP沒有標準
方法來指定訊息的目的地址、如何返迴響應以及錯誤在哪等。如果訊息互動變得複雜一點,這種問題
就無法解決。如:由用戶端發出去的訊息需經過多個服務路由處理。
WebService定址規範正是為瞭解決這些問題。在WebService定址規範中有兩個重要的概念:
終結點應用、訊息報 頭。它可以用於在WebService中傳達Service Endpoint所需要的資訊,
也可為訊息在WebService間傳送提供地址。
如下所示顯示終結點應用所需的資訊集
<wsa:EndpointReference>
<wsa:Address>xs:anyURI</wsa:Address>
<wsa:ReferenceProperties>... </wsa:ReferenceProperties> ?
<wsa:ReferenceParameters>... </wsa:ReferenceParameters> ?
<wsa:PortType>xs:QName</wsa:PortType> ?
<wsa:ServiceName PortName="xs:NCName"?>xs:QName</wsa:ServiceName> ?
<wsa:Policies> ... </wsa:Policies>?
<xs:any/>*
</wsa:EndpointReference>
在終結點應用所需的資訊集中只有<wsa:Address>xs:anyURI</wsa:Address>是必須的,其他幾個都是可選的。
訊息前序:它是WebService定址中定義了一些標準的SOAPHeader,它擴充並添加到SOAPHeader中。
2、邏輯地址與物理地址物理地址是ServiceEndpoint的ListenUri屬性指明的值,也就是監聽地址;邏輯地址則是端點位址,
即EndpointAddress,即SOAP訊息的"To"指向的地址。
public class ServiceEndpoint
{
// Fields
private EndpointAddress address;
private Uri listenUri;
private ListenUriMode listenUriMode;
//其他屬性
}
WCF用戶端與服務端互動是通過物理地址,即監聽地址實現的。在WCF中,服務通過物理地址
在制定的位置監聽傳入的訊息。在WCF配置中,<endpoint>元素中address屬性指定的即為邏輯
地址;listenUri指定物理地址。除非通過listenUri指定,一般邏輯地址與物理地址是相同的。
如果服務端配置了物理地址,在用戶端通過ClientViaBehavior告之Client服務端所使用的物理地址。
Server端配置如下:
<endpoint
address="net.tcp://127.0.0.1:9999/CalculatorService"
binding="netTcpBinding" contract="Contracts.ICalculator" listenUri="net.tcp://127.0.0.1:3333/CalculatorService" />
Client端配置如下:
<behaviors><endpointBehaviors><behavior name="myNetTcp"><clientVia viaUri ="net.tcp://127.0.0.1:3333/CalculatorService"/></behavior></endpointBehaviors></behaviors><endpoint address="net.tcp://127.0.0.1:9999/CalculatorService" binding="netTcpBinding" contract="Contracts.ICalculator" name="calculatorService" behaviorConfiguration="myNetTcp" ></endpoint>
使用物理地址,用戶端通過與服務端相同的物理地址發送訊息。那麼邏輯地址有什麼用呢。?看看
EndpointAddressMessageFilter的Match方法的簽名:
public override bool Match(Message message)
{
if (message == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");
}
Uri to = message.Headers.To;
Uri uri = this.address.Uri;
return (((to != null) && this.comparer.Equals(uri, to)) && this.helper.Match(message));
}
public override bool Match(MessageBuffer messageBuffer)
{
bool flag;
if (messageBuffer == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageBuffer");
}
Message message = messageBuffer.CreateMessage();
try
{
flag = this.Match(message);
}
finally
{
message.Close();
}
return flag;
}通過Match方法,我們可知:ChannelDispatcher通過遍曆EndpointDispatcher以確定將訊息發送到哪一個EndpointDispatcher時,使用邏輯地址進行判斷。3、基地址、相對位址、絕對位址在WCF中,通過基地址技術可以為不同的Endpoint方便的配置不同的地址邏輯地址。
基地址、相對位址、絕對位址都是相對Endpoint來說的。
3.1 基地址:
在<host>下的子項目<baseAddresses>下通過<add>指定,如下:
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:8888/Calculator"/>
</baseAddresses>
</host>
3.2 相對位址:
在<Endpoint >的<Address>屬性中指定非完全限定地址。使用基地址時就無需為<Endpoint >指定絕對位址了。如下:
<endpoint address="Service" binding="basicHttpBinding" contract="Contracts.ICalculator" ></endpoint>
3.3 絕對位址:
直接在<Endpoint >的<Address>屬性指定的終結點的完全限定地址。如:“
<endpoint
address="http://127.0.0.1:8888/CalculatorServices"
binding="basicHttpBinding" contract="Contracts.ICalculator" >
</endpoint>
看看對基地址、相對位址、絕對位址作如下配置是什麼結果:
<endpoint
address=""
binding="basicHttpBinding" contract="Contracts.ICalculator" >
</endpoint>
<endpoint
address="Service"
binding="basicHttpBinding" contract="Contracts.ICalculator" >
</endpoint>
<endpoint
address="http://127.0.0.1:8888/CalculatorServices"
binding="basicHttpBinding" contract="Contracts.ICalculator" >
</endpoint>
<endpoint
address="http://127.0.0.1:9999/CalculatorService"
binding="basicHttpBinding" contract="Contracts.ICalculator" listenUri="http://127.0.0.1:3333/CalculatorService" listenUriMode="Unique">
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:8888/Calculator"/>
</baseAddresses>
</host>
通過C# 控制台看看地址資訊:
ServiceDescription serviceDescription = host.Description;
ServiceEndpointCollection serviceEndpoints = serviceDescription.Endpoints;
foreach (var serviceEndpoint in serviceEndpoints)
{
Console.WriteLine("----------------------------");
Console.WriteLine("邏輯地址:"+serviceEndpoint.Address.Uri);
Console.WriteLine("物理地址:" + serviceEndpoint.ListenUri);
}
輸出如下: