WCF後傳系列(2):深入WCF尋址Part 2—自定義尋址報頭

概述

WCF專題系列(1):深入WCF尋址Part1一文中,我們對Web服務尋址規範做了一些認識,瞭解了終結點引用和消息信息報頭兩種結構,該規範在Web服務中的地位舉足輕重,後續我們會經常提到該規範。在本文中,我們將繼續深入WCF尋址的內容,包括元數據中的終結點地址,自定義尋址標頭等相關信息。

終結點地址定義

瞭解了Web服務尋址規範,再回到WCF,在WCF中,終結點地址是由EndpointAddress類來表示的,它其中很重要的幾個部分是:一個表示服務地址的統一資源定位符 (URI),一個表示服務的安全標識的 Identity 和一個可選的 Headers 集合,其中Headers用於標識終結點或與終結點交互的更多詳細尋址信息。如圖1所示:
TerryLee_WCF_02  
圖1
記的我在WCF專題系列(1):深入WCF尋址Part1一文提到過,每個終結點引用都可以包含一些添加額外標識信息的引用參數,即尋址標頭,在 WCF 中,將這些引用參數建模爲 AddressHeader 類的實例,這裏的Headers屬性就是這些實例的集合,可以通過AddressHeader類提供的靜態方法CreateAddressHeader來創建一個AddressHeader實例,如下代碼所示:
AddressHeader header = AddressHeader.CreateAddressHeader("basic",
                        "http://www.cnblogs.com/terrylee", "Terrylee");

指定終結點地址

在WCF中提供了基址技術,這使的我們在指定終結點地址時可以酌情選用相對地址或者絕對地址,指定絕對地址的方法是在終結點定義中提供完全限定的地址,如下代碼所示:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <endpoint address="[url]http://localhost:8887/CalculatorService[/url]"
            binding ="basicHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
</service>
使用絕對地址固然簡單,但是如果我們的服務需要公開多個終結點,而這些終結點地址又具有相同的基地址時,也許相對地址是更好的選擇。在創建服務宿主對象時,提供一個基地址,如下代碼所示:
using (ServiceHost calculatorServiceHost =
        new ServiceHost(typeof(CalculatorService),
        new Uri("http://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="[url]http://localhost:8887/Calculator[/url]"/>
    </baseAddresses>
  </host>
  <endpoint address="myservice1"
            binding ="basicHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
  <endpoint address="myservice2"
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
</service>
但請注意,基址技術是爲我們在配置終結點時提供了方便,客戶端對它是毫無所知的,客戶端看到的仍然是絕對地址,在打開服務宿主時,它會匹配所有的相對地址,從而爲每個終結點提供相應的絕對地址,如上面的示例,可以在WSDL中看到:
<wsdl:service name="CalculatorService">
  <wsdl:port name="BasicHttpBinding_ICalculator" binding="tns:BasicHttpBinding_ICalculator">
    <soap:address location="[url]http://localhost:8887/Calculator/myservice1[/url]" />
  </wsdl:port>
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="[url]http://localhost:8887/Calculator/myservice2[/url]" />
    <wsa10:EndpointReference>
      <wsa10:Address>[url]http://localhost:8887/Calculator/myservice2[/url]</wsa10:Address>
      <Identity xmlns="[url]http://schemas.xmlsoap.org/ws/2006/02/addressingidentity[/url]">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>
如果在指定了基地址的情況下,有以下幾種情況:指定相對地址爲空,終結點地址與基地址相同;指定相對地址不爲空,追加相對地址到基地址上;指定一個絕對地址,基地址不起作用,終結點地址仍然爲指定的絕對地址;指定一個絕對地址和一個與基地址不同的綁定,基地址不起作用。現在有這樣一段配置信息:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="[url]http://localhost:8887/Calculator[/url]"/>
    </baseAddresses>
  </host>
  <endpoint address=""
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
  <endpoint address="myservice2"
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
  <endpoint address="[url]http://localhost:8886/CalculatorService[/url]"
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
  <endpoint address="net.tcp://localhost:8885/Calculator"
            binding ="netTcpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
  </endpoint>
</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所示:
TerryLee_WCF_05  
圖2

元數據中終結點地址

終結點地址在WSDL中表示爲對應終結點的 wsdl:port元素內的終結點引用(EndpointReference)元素。終結點引用包含終結點的地址以及所有的地址屬性,如下示例代碼所示:
<wsdl:service name="CalculatorService">
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="[url]http://localhost:8887/Calculator[/url]" />
    <wsa10:EndpointReference>
      <wsa10:Address>[url]http://localhost:8887/Calculator[/url]</wsa10:Address>
      <Identity xmlns="[url]http://schemas.xmlsoap.org/ws/2006/02/addressingidentity[/url]">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>

自定義尋址報頭

在本文的終結點定義一節,我們提到了尋址報頭,在某些情況下,我們可能希望通過自定義尋址報頭來解決一些複雜的問題,如根據根據傳入的尋址報頭中是否包含某些信息,將其轉發到不同的終結點,通過自定義尋址報頭,可以實現SOAP消息的無限擴展,放置任何希望的控制信息到SOAP消息。如下面的代碼:
using (ServiceHost calculatorServiceHost =
    new ServiceHost(typeof(CalculatorService),
    new Uri("http://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",
        "http://www.cnblogs.com/terrylee", "Terrylee");
    EndpointAddress ea = new EndpointAddress(
        new Uri("http://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中可以看到該自定義的報頭,它作爲終結點引用的引用參數:
<wsdl:service name="CalculatorService">
  <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
    <soap12:address location="[url]http://localhost:8887/CalculatorService[/url]" />
    <wsa10:EndpointReference>
      <wsa10:Address>[url]http://localhost:8887/CalculatorService[/url]</wsa10:Address>
      <wsa10:ReferenceParameters>
        <basic xmlns="[url]http://www.cnblogs.com/terrylee[/url]">Terrylee</basic>
      </wsa10:ReferenceParameters>
      <Identity xmlns="[url]http://schemas.xmlsoap.org/ws/2006/02/addressingidentity[/url]">
        <Upn>TerryLee-PC\TerryLee</Upn>
      </Identity>
    </wsa10:EndpointReference>
  </wsdl:port>
</wsdl:service>
截獲到SOAP消息可以看到,在消息報頭中添加了basic這樣的信息,如下代碼所示:
<s:Envelope xmlns:s="[url]http://schemas.xmlsoap.org/soap/envelope/[/url]">
  <s:Header>
    <basic xmlns="[url]http://www.cnblogs.com/terrylee[/url]">Terrylee</basic>
    <To s:mustUnderstand="1">[url]http://localhost:8887/CalculatorService[/url]</To>
    <Action s:mustUnderstand="1">[url]http://tempuri.org/ICalculator/Add[/url]</Action>
  </s:Header>
  <s:Body>
    <Add xmlns="[url]http://tempuri.org/[/url]">
      <x>1</x>
      <y>2</y>
    </Add>
  </s:Body>
</s:Envelope>
當然我們也可以通過配置的方式來自定義尋址報頭,如下代碼所示:
<service name="TerryLee.WCFAddressing.Service.CalculatorService"
         behaviorConfiguration="calculatorBehavior">
  <host>
    <baseAddresses>
      <add baseAddress="[url]http://localhost:8887/Calculator[/url]"/>
    </baseAddresses>
  </host>
  <endpoint address=""
            binding ="wsHttpBinding"
            contract="TerryLee.WCFAddressing.Contract.ICalculator">
    <headers>
      <basic xmlns="[url]http://www.cnblogs.com/terrylee[/url]">Terrylee</basic>
    </headers>
  </endpoint>
</service>

結束語

本文相對於WCF專題系列(1):深入WCF尋址Part1來說,注重於實際的使用,介紹了指定終結點地址、元數據中的終結點地址、自定義消尋址報頭等,在下一篇中,我們將繼續深入WCF尋址,探討消息篩選器等問題。WCF尋址相關文章:

0

收藏

lihuijun

180篇文章,72W+人氣,0粉絲

Ctrl+Enter 發佈

發佈

取消

掃一掃,領取大禮包

0

分享
lihuijun
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章