程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF專題系列(5):深入WCF尋址Part 5—邏輯地址和物理地址

WCF專題系列(5):深入WCF尋址Part 5—邏輯地址和物理地址

編輯:關於.NET

概述

在WCF中,每個服務終結點都與兩個地址相關聯,一個邏輯地址和一 個物理地址,邏輯地址就是SOAP消息的目標地址,即前面不止一次提到的 “To”地址,而物理地址是WCF偵聽器真正監聽的地址。在WCF中,邏 輯地址稱之為終結點地址Endpoint Address,而物理地址則稱之為監聽地址 ListenUri。

兩種地址

WCF中,物理地址負責使用特定的傳輸協議在特 定的位置接收傳入的消息,除非特別指定,否則邏輯地址將被用來做物理地址, 換句話說,在以前我們對於終結點所配置的EndpointAddress都是指定了邏輯地 址,如我們的服務端配置如下:

<endpoint address="http://localhost:8887/CalculatorService1"
      binding ="wsHttpBinding"
      contract="TerryLee.WCFAddressing.Contract.ICalculator"></endpoint>
<endpoint address="http://localhost:8887/CalculatorService2"
      binding ="basicHttpBinding"
      contract="TerryLee.WCFAddressing.Contract.ICalculator"></endpoint>

現在我們輸出一下,就可以看到兩個地址是 同樣的值,如下代碼所示:

using (ServiceHost calculatorServiceHost =
    new ServiceHost(typeof (CalculatorService)))
{
  calculatorServiceHost.Opened += delegate
  {
    Console.WriteLine("Service begin to listen via the Address:{0}",
       calculatorServiceHost.BaseAddresses[0].ToString());
  };
  calculatorServiceHost.Open();
  foreach (ServiceEndpoint se in calculatorServiceHost.Description.Endpoints)
  {
     Console.WriteLine("Endpoint details:");
     Console.WriteLine("Logical address: \t{0}", se.Address);
    Console.WriteLine("Physical address: \t{0}", se.ListenUri);
    Console.WriteLine("Binding: \t{0} ", se.Binding.Name);
    Console.WriteLine();
   }
  Console.Read();
}

輸出結果如圖1所示:

圖1

設定物理地址

前面我們輸出的結果邏輯地址和物理地址 是相同的,我們可以通過代碼或者配置文件來設定終結點的物理地址。

WSHttpBinding wsbinding = new WSHttpBinding();
calculatorServiceHost.AddServiceEndpoint(
  typeof (ICalculator),
  wsbinding,
   "urn:calcservice", // 邏輯地址
  new Uri ("http://localhost:8887/CalculatorService") // 物理地址
);

又或者通過配置文件來設置ListenUri,如下代碼所示:

<endpoint address="urn:calcservice"
      binding ="wsHttpBinding"
      contract="TerryLee.WCFAddressing.Contract.ICalculator"
      listenUri="http://localhost:8887/CalculatorService"
      bindingConfiguration="securityBinding">
</endpoint>

這裡我們只需要注意的是在指定物理地址時, 仍然可以使用相對地址,這一點與設置邏輯地址時是一樣的。

工作原理

現在思考一個核心的問題,當我們定義了終結點後,在WSDL中包含的是每個 終結點的邏輯地址,而非物理地址,如下代碼片段:

<wsdl:service name="CalculatorService">
 <wsdl:port name="WSHttpBinding_ICalculator" binding="tns:WSHttpBinding_ICalculator">
   <soap12:address location="urn:calcservice" />
   <wsa10:EndpointReference>
    <wsa10:Address>urn:calcservice</wsa10:Address>
   </wsa10:EndpointReference>
 </wsdl:port>
</wsdl:service>

如果物理地址與邏輯地址相同的,就不會 有任何問題,但是客戶端如何與一個配置了不同物理地址的服務進行交互?因為 客戶端並不關心服務端是否配置了不同的物理地址,它只知道每個終結點有一個 唯一的終結點地址,只需要跟該地址交互即可,該地址也將作為SOAP消息放在 “To”標頭中。

這時我們需要有一個特殊機制,來通知客戶 端要使用的物理地址,然後客戶端通過物理地址傳送外發消息,就如同它是路由 器或者某種類型的中介一樣,可以通過ClientViaBehavior來實現這一點,如下 代碼所示:

<system.serviceModel>
  <client>
  <endpoint address="urn:calcservice"
        binding="wsHttpBinding"
        contract="TerryLee.WCFAddressing.Contract.ICalculator"
       name="defualtEndpoint"
        behaviorConfiguration="calculatorEndpointBehavior"
        bindingConfiguration="securityBinding">
   </endpoint>
 </client>
 <behaviors>
  <endpointBehaviors>
   <behavior name="calculatorEndpointBehavior">
     <clientVia viaUri="http://localhost:8887/CalculatorService" />
   </behavior>
  </endpointBehaviors>
  </behaviors>
</system.serviceModel>

此時客戶 端將通過與服務終結點相同的物理地址 (http://localhost:8887/CalculatorService)向外傳送消息而不是通過 “urn:calcservice”,但請注意,在SOAP消息“To”標 頭中包含的仍然是邏輯地址,如圖2所示:

圖2

看到上面這幅圖,可能大家還有一個疑問,邏輯地址起什 麼作用呢?別忘了我們前面講到的消息篩選,當消息到達時, ChannelDispatcher 查詢每個相關的 EndpointDispatcher 對象以確定終結點是 否可以接受消息,以及將該消息傳遞到可以接受消息的終結點。當消息的目標地 址(To標頭中的地址)與 AddressFilter 屬性相匹配並且消息操作與 ContractFilter 屬性相匹配時,EndpointDispatcher 對象負責處理來自 ChannelDispatcher 的消息。

物理地址模式

了解了物理地址和邏輯地 址之間的關系,我們再看一下在設置監聽地址時的兩種模式,通過 ListenUriMode枚舉來指定,它定義了兩個枚舉值:

Explicit:完全原樣 使用 ListenUri,默認值。

Unique:指定傳輸是否應使用特定傳輸機制 ,以確保 ListenUri 是唯一的

根據傳輸所采用的協議不同,WCF會采用 不同的策略來保證ListenUri唯一,具體的策略如下所示:

1.非TCP傳輸 ,在ListenUri的末尾附加一個GUID。

2.對於獨占模式下的 TCP (PortSharingEnabled 為 false),綁定到一個唯一可用端口號。

3.對 於端口共享模式下的 TCP(PortSharingEnabled 為 true),在ListenUri的末 尾附加一個GUID。

TcpTrace消息截獲

前面講了這麼多物理地址和邏輯 地址,它們最重要的使用地方就是做路由。我們常用tcpTrace來做SOAP消息跟蹤 ,它正是利用這一點技術,在客戶端配置ClientViaBehavior,指向tcpTrace的 偵聽地址,然後tcpTrace在對消息做記錄後再轉發到服務端,如在服務端的配置 如下,它的物理地址和邏輯是相同的:

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

客戶端的配置, 這裡“http://localhost:8887/CalculatorService”是真正的服務 地址(邏輯地址),我們通過ClientViaBehavior告訴客戶端物理地址是 “http://localhost:8080/CalculatorService”,事實上處於該物 理地址的服務並不存在,該地址是tcpTrace的監聽地址:

<? xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
   <client>
   <endpoint address="http://localhost:8887/CalculatorService"
         binding="wsHttpBinding"
         contract="TerryLee.WCFAddressing.Contract.ICalculator"
         behaviorConfiguration="calculatorEndpointBehavior">
   </endpoint>
  </client>
   <behaviors>
   <endpointBehaviors>
     <behavior name="calculatorEndpointBehavior">
      <clientVia viaUri="http://localhost:8080/CalculatorService" />
    </behavior>
   </endpointBehaviors>
  </behaviors>
 </system.serviceModel>
</configuration>

tcpTrace的配置如圖3所示:

圖3

這裡tcpTrace監聽的端口號就是我們在客戶端配置的物理 地址端口號,而分發地址才是服務的真正地址,最終可以看到截獲的消息,如圖 4所示:

圖4

如果不在客戶端配置ClientViaBehavior,利用物理地址和 邏輯地址的知識,我們還可以有另外一種方式使用tcpTrace。前面我說過,邏輯 地址是包含在WSDL中,所以對於客戶端來說知道的是邏輯地址,它會向該地址發 送消息,這樣我們可以配置終結點的邏輯地址為tcpTrace偵聽的地址,而為服務 端指定另外一個物理地址,並配置tcpTrace向該物理地址轉發消息,如服務端的 配置如下:

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

而客戶端則不用再 配置ClientViaBehavior,如下代碼所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <system.serviceModel>
   <client>
   <endpoint address="http://localhost:8887/CalculatorService"
         binding="wsHttpBinding"
         contract="TerryLee.WCFAddressing.Contract.ICalculator">   </endpoint>
  </client>
  </system.serviceModel>
</configuration>

現在 “http://localhost:8887/CalculatorService”是邏輯地址,配置 tcpTrace監聽該地址,並向服務的物理地址 “http://localhost:8080/CalculatorService”轉發消息,如圖5所 示:

圖5

可以看到,利用物理地址和邏輯地址的知識,可以輕松的 實現路由,當然tcpTrace只是路由中非常簡單的一種使用,後面我們還會講到更 加復雜的應用。

結束語

本文詳細介紹了WCF中的物理地址和邏輯地址 ,它的相關原理以及如何使用tcpTrace來實現SOAP消息的跟蹤。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved