首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 專題系列(二):深入 WCF 定址 Part 2 — 自訂定址標頭

     編輯:關於.NET

在上一篇「WCF 專題系列(一):深入 WCF 定址 Part 1」中,我們已認識 Web 服務定址規範(WS-Addressing),了解端點參考(Endpoint Reference)與訊息資訊標頭兩大核心結構。這個規範在 Web 服務架構中舉足輕重,後續內容將持續引用。本文將繼續深入 WCF 定址機制,重點探討中繼資料中的端點位址、自訂定址標頭等實務應用。

端點位址定義

回到 WCF 架構,端點位址由 EndpointAddress 類別表示,主要包含三個關鍵部分:服務位置的統一資源識別符(URI)、代表服務安全身分的 Identity,以及可選的 Headers 集合。Headers 用於攜帶識別端點或與端點互動所需的額外定址資訊,如圖 1 所示:

圖 1:EndpointAddress 類別結構示意

在上一篇提到,每個端點參考可包含提供額外識別資訊的參考參數,即定址標頭。在 WCF 中,這些參考參數被建模為 AddressHeader 類別的執行個體,Headers 屬性即為這些執行個體的集合。可透過 AddressHeader.CreateAddressHeader 靜態方法建立標頭實例,程式碼如下:

AddressHeader header = AddressHeader.CreateAddressHeader(
    "basic",
    "https://www.cnblogs.com/terrylee",
    "Terrylee");

指定端點位址

WCF 提供基底位址技術,讓我們在定義端點位址時可彈性選擇相對或絕對路徑。使用絕對位址最直接,直接在端點定義中給出完整 URL:

<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <endpoint address="https://localhost:8887/CalculatorService"
            binding="basicHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator" />
</service>

若服務需公開多個共用相同基底位址的端點,使用相對位址更為優雅。在建立 ServiceHost 時指定基底位址:

using (ServiceHost calculatorServiceHost = 
    new ServiceHost(typeof(CalculatorService),
    new Uri("https://localhost:8887/CalculatorService")))
{
    calculatorServiceHost.Opened += delegate
    {
        Console.WriteLine("Service begin to listen via the Address:{0} ",
            calculatorServiceHost.BaseAddresses[0].ToString());
    };
    calculatorServiceHost.Open();
    Console.Read();
}

或在組態檔中集中設定基底位址,端點僅需提供相對路徑:

<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="https://localhost:8887/Calculator" />
    </baseAddresses>
  </host>
  <endpoint address="myservice1"
            binding="basicHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator" />
  <endpoint address="myservice2"
            binding="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator" />
</service>

需注意:基底位址僅簡化伺服器端設定,客戶端仍看到完整絕對位址。服務啟動時會自動解析相對位址,產生對應的絕對位址,這在 WSDL 中可明確觀察:

<wsdl:service name="CalculatorService">
  <wsdl:port name="BasicHttpBinding_ICalculator" binding="tns:BasicHttpBinding_ICalculator">
    <soap:address location="https://localhost:8887/Calculator/myservice1" />
  </wsdl:port>
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="https://localhost:8887/Calculator/myservice2" />
    <wsa10:EndpointReference>
      <wsa10:Address>https://localhost:8887/Calculator/myservice2</wsa10:Address>
      <Identity xmlns="https://schemas.xmlsoap.org/ws/2006/02/addressingidentity">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>

基底位址與相對/絕對位址的交互規則

  • 相對位址為空:端點位址等於基底位址
  • 相對位址非空:端點位址 = 基底位址 + 相對位址
  • 指定絕對位址:基底位址失效,端點位址為指定的絕對位址
  • 指定絕對位址且綁定與基底位址配置不同:基底位址失效

以下組態範例展示混合情況:

<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="https://localhost:8887/Calculator" />
    </baseAddresses>
  </host>
  <endpoint address="" binding="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator" />
  <endpoint address="myservice2" binding="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator" />
  <endpoint address="https://localhost:8886/CalculatorService" binding="wsHttpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator" />
  <endpoint address="net.tcp://localhost:8885/Calculator" binding="netTcpBinding" contract="TerryLee.WCFAddressing.Contract.ICalculator" />
</service>

啟動 ServiceHost 後,透過以下程式碼可列出所有端點的實際位址與綁定:

ServiceDescription desc = calculatorServiceHost.Description;
foreach (ServiceEndpoint endpoint in desc.Endpoints)
{
    Console.WriteLine("Endpoint - address: {0}", endpoint.Address);
    Console.WriteLine(" binding: {0}", endpoint.Binding.Name);
    Console.WriteLine(" contract: {0}", endpoint.Contract.Name);
}

執行結果如圖 2 所示:

圖 2:端點位址與綁定資訊輸出

中繼資料中的端點位址

端點位址在 WSDL 中以對應 wsdl:port 元素內的端點參考(EndpointReference)呈現,包含端點位址及所有定址屬性:

<wsdl:service name="CalculatorService">
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="https://localhost:8887/Calculator" />
    <wsa10:EndpointReference>
      <wsa10:Address>https://localhost:8887/Calculator</wsa10:Address>
      <Identity xmlns="https://schemas.xmlsoap.org/ws/2006/02/addressingidentity">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>

自訂定址標頭

某些情境下,我們需要透過自訂定址標頭解決複雜路由問題,例如依據傳入 SOAP 標頭中的特定資訊,將訊息轉發至不同端點。自訂標頭能實現 SOAP 訊息的無限擴展,將任意控制資訊置入標頭。以下程式碼示範以程式碼方式新增自訂標頭:

using (ServiceHost calculatorServiceHost = 
    new ServiceHost(typeof(CalculatorService),
    new Uri("https://localhost:8887/CalculatorService")))
{
    calculatorServiceHost.Opened += delegate
    {
        Console.WriteLine("Service begin to listen via the Address:{0} ",
            calculatorServiceHost.BaseAddresses[0].ToString());
    };
    
    AddressHeader header = AddressHeader.CreateAddressHeader("basic",
        "https://www.cnblogs.com/terrylee", "Terrylee");
    
    EndpointAddress ea = new EndpointAddress(
        new Uri("https://localhost:8887/CalculatorService"), header);
    
    calculatorServiceHost.Description.Endpoints.Add(
        new ServiceEndpoint(
            ContractDescription.GetContract(typeof(ICalculator)),
            new WSHttpBinding(),
            ea));
    
    ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    behavior.HttpGetEnabled = true;
    calculatorServiceHost.Description.Behaviors.Add(behavior);
    calculatorServiceHost.Open();
    Console.Read();
}

產生的 WSDL 中,自訂標頭會作為端點參考的參考參數(ReferenceParameters)出現:

<wsdl:service name="CalculatorService">
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="https://localhost:8887/CalculatorService" />
    <wsa10:EndpointReference>
      <wsa10:Address>https://localhost:8887/CalculatorService</wsa10:Address>
      <wsa10:ReferenceParameters>
        <basic xmlns="https://www.cnblogs.com/terrylee">Terrylee</basic>
      </wsa10:ReferenceParameters>
      <Identity xmlns="https://schemas.xmlsoap.org/ws/2006/02/addressingidentity">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>

實際攔截的 SOAP 訊息標頭中,也會包含該自訂資訊:

<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <basic xmlns="https://www.cnblogs.com/terrylee">Terrylee</basic>
    <To s:mustUnderstand="1">https://localhost:8887/CalculatorService</To>
    <Action s:mustUnderstand="1">https://tempuri.org/ICalculator/Add</Action>
  </s:Header>
  <s:Body>
    <Add xmlns="https://tempuri.org/">
      <x>1</x>
      <y>2</y>
    </Add>
  </s:Body>
</s:Envelope>

同樣也可透過組態檔宣告式方式設定自訂標頭:

<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="https://localhost:8887/Calculator" />
    </baseAddresses>
  </host>
  <endpoint address=""
            binding="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
    <headers>
      <basic xmlns="https://www.cnblogs.com/terrylee">Terrylee</basic>
    </headers>
  </endpoint>
</service>

結語

本文承接第一篇,著重於 WCF 定址的實務操作:指定端點位址(含基底位址技術)、中繼資料中的端點呈現、以及自訂定址標頭的程式碼與組態兩種實作方式。下一篇將繼續探討訊息篩選器等進階主題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved