WCF 實戰開發系列 (二) - 如何使用 Routing Service 實作動態路由與訊息的篩選

如何使用 Routing Service 實作動態路由與訊息的篩選

前言

上一次,筆者撰寫了一篇「WCF 開發實戰(一)」,為 WCF 的所有功能做了基本的介紹,而目前 WCF 雖然在市場比較少有企業有相關的需求,目前光芒似乎都被 SignalR 或 Web Socket 或 Web API 給蓋過去了,但事實上,WCF 在企業內部仍有許多不可取代性的功能,比如 Routing Service 就是其中之一的功能。

今天,筆者要介紹的是 WCF 4.0 才加入的 Routing Service 的功能

大綱

  • WCF Routing Services 概觀
  • 如何使用 WCF Routing Service
    • 如何掛載 Routing Service
    • 如何設定 Routing Service Endpoint(s)
    • 如何設定 Routing Service Message Filter(s)
    • 如何設定 Routing Service Target Service(s)
    • 如何定義 Routing Service 的 Filter Table
  • Routing Service 的相關特性說明
  • Demo the Routing Service
  • 一個 Routing Service 使用 MatchAll 與 filterType 的範例說明
  • 以內容為基礎的 Routing Service
    • Content Based Routing using the Action Values
    • Content Based Routing using the XPath Expressions
  • 路由的動態更新 Dynamic Routing Service
  • 常見的路由案例

 

開始之前

在開始之前筆者先介紹使用環境,因為本文章到最後會有一個簡單的 Routing Service 的範例

環境:Windows 10 企業版 (版本:1511)

工具:Visual Studio 2015 Update3

 

WCF Routing Services 概觀

首先,我們先來瞭解一下,什麼是 WCF Routing Service 呢? (以下都簡稱 Routing Service),所謂的 Routing Service 是 WCF 4.0 後所新增的功能,它是一個以 SOAP 訊息為基礎的服務器,Routing Service 可以依據你的 Filter 定義將傳入的 SOAP 訊息導向到您內部網路的任一台服務器,它的好處在於,可以方便讓企業自行規劃實際要提供的伺服器是哪一台,也就是說,使用 Routing Service 讓您比較容易在企業內部實作集中式管控(Centralized Security Bund) 或負載平衡(Load-Balancing) 的架構。

在前一篇文章「WCF 開發實戰系列(一)」中,筆者說明了 WCF 所有支援的通信協定,而一般來說,在 Routing Service 中,您可以在所有支援的通訊協定下,在單工 (one-way) 與雙工 (Duplex Messaging) 使用不同的 Message Filter (稍後我會說明 Message Filter)

 

要如何使用 WCF Routing Service?

要使用 Routing Service 的服務需要在掛載 Host 初始化時提供 ServiceType,且 Routing Service 中的 ServiceContract 由服務所提供,一共提供了四種介面,也就是說,要使用 Routing Service 您得先瞭解這四個介面:

下面程式碼是 WCF Routing Service 類別的原型:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, 
       InstanceContextMode = InstanceContextMode.PerSession, UseSynchronizationContext = false, ValidateMustUnderstand = false)]
public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter, IDisposable
{
}

ISimplexDatagramRouter 與 IRequestReplyRouter 是應用在大部分基本 WCF 服務應用方式,單向回呼的操作,而 ISimplexSessionRouter 基本上是一個發射後不理的操作,會在一個對話的範圍內進行,而IDuplexSessionRouter 基本上是需要回呼到對話範圍內的 Client 端應用程的雙工作業。

 

如何掛載 Routing Service?

下面使用 Self-Hosing 的方式來掛載一個支援 Routing Service 的服務

 

如何設定 Routing Service Endpoint(s)

一般來說,您可以設定一個到多個的 Endpoint(s) 給你的 RoutingService 使用,您的 Service Contract 可使用在前面所提的4種介面,下面是一個設定 2 個 Endpoint(s) 的 Routing Service 的範例:

 

如何設定 Routing Service Target Service(s)

如上面的 Routing Service Endpoint(s) 的範例,我們使用的是 basicHttpBinding 的與 IRequestReplyRouter 服務合約,接著我們只需要定義可連結到這個服務端的 Target Service(s) 也就是對遠端繞送過的訊息,對  Routing Service 的服務器來說,實際的服務氣端是它的是用戶端 (Client) 的端點,如下是這個 RoutingService 的用戶端的端點。

如何設定 Routing Service Message Filter(s)

您可以使用 WCF 提供的 RoutingBehavior 來配置 RoutingService 的訊息過濾器 (Message Filters),接著你必須再指定一個 Behavior name 並讓 RoutingService 使用這個 Configuration,如下圖所示:

然後就是將 <serviceBehavior> 的 filterTableName 對應到 <filterTable> 的名稱

如何定義 Routing Service 的 Filter Table?

要定義 Routing Service 的 Filter Table 之前,我們先來了解一下什麼是 Filter Table?Filter Table 就是定義當 Routing Service 服務器端收到一個 Endpoint 端點的呼叫的時候,路由該如何繞送、以及該使用何種 filterType 塞選條件類型。也就是說,每個 filter 定義 Routing filter 和目標端點 (Endpoint)之間的對應

如下,是設定兩個 filter 對應到兩個 Endpoint(s) 的範例:

另外,在 WCF 4.0 Routing Service 中所有支援的 filterType 如下:

一般來說,為實作 (Content Base Routing) 內容架構路由,路由服務會使用 MessageFilter 實作,該實作會檢查訊息的特定區段,例如位址、端點名稱或特定 XPath 陳述式。而在設定路由服務時,您必須定義篩選項目 FilterElement 物件為何,因為每個篩選資料表中的每個項目都會參考篩選項目 FilterElement,並且指定將路由傳送訊息的目標用戶端端點 (前提是如果訊息符合篩選的話)。

且當傳送至主要端點期間發生傳輸失敗事件時,會依指定的順序嘗試這些端點,直到其中一個成功為止

如上圖中的倒數第二項「MatchAll」會允許所有訊息通過篩選條件,下面是一個 MatchAll 範例:

WCF Routung Service 中的各種 MessageFilter

所有 Filter 均由 MessageFilter 延伸而來,並提供回傳IMessageFilterTable<TFilterData>的 CreateFilterTable 方法

  • XPathMessageFilter

會使用 XML 規範中的 XPath 1.0 運算式來指定比對的準則

  • MatchAllMessageFilter

會比對所有訊息,並允許所有訊息通過的篩選條件

  • MatchNoneMessageFilter

不會比對任何一個訊息

  • ActionMessageFilter

會測試訊息的動作是否為指定動作集中的動作

  • EndpointAddressMessageFilter

會測試訊息是否符合指定的端點位址

 

以內容為基礎的 Routing Service (Content Base Routing)

所謂的 Content Based Routing 是指您可以在 Route經由訊息 (Message) 的『內容』來決定要將訊息轉送到哪一個服務端點 (Service endpoint),也就是說,您可以在傳入的 SOAP 訊息內的 Header 或 Body 如果包含特定內容時轉送到某個 Endppoint 端點中。

一般來說 Content Based Routing 又可區分為兩種:

  • Action (Content Based Routing using the Action Values)
    • 這是根據動作類型,來決定要繞送的 Endpoint 端點位置
  • XPath (Content Based Routing using the XPath Expressions)
    • 這是根據動作的訊息 (SOAP) 內容,來決定要繞送的 Endpoint 端點位置

 

Content Based Routing using the Action Values

首先,我們先來看看 Action 類型的設定方式,如下,我先設定兩個 Routing Service 的用戶端端點:

如上圖的端點名稱,一個負責 Binary 另一個負責 Unary 的呼叫

這邊所有的 filterType = "Action" ,這表示我可以經由動作名稱來決定要繞送端點的呼叫到哪裡去,非常有意思吧!這麼一來,我可以任意的決定、定義企業內部的呼叫邏輯、商業邏輯(Ap Server) 的實際位置、以及根據 Loading 來規劃適合或足夠硬體設備的 Ap Server 來提供服務。

它的 filterTable 設定如下:

 

Content Based Routing using the XPath Expressions

在 Routing Service 中,我們也可以根據訊息的內容,來決定繞送方式,各位或許會好奇為什麼是 XPath?這其實是因為既然是 Content Base,那 WCF 實際的 Content 是什麼呢?沒錯,這跟 Web Service 相同,就是 SOAP,而 SOAP 是 XML Schema 所定義的,XPath 是 W3C 的標準之一,XPath 是提供我們尋覽 XML Document 的一種方式,它也是作業在 XLST 標準的主要元素,XPath 的功能也都已經含括在所有標準的 XML SDK 套件裡。

而使用 XML 的 XPath 來尋覽 SOAP 內容的 filterTable、且並又設定為路由的 filter,這稱作 XPath Expression,在實際使用時,必須在 routing 設定中綁定前綴詞 prefix

實際的 SOAP 封包如下:

綠色框起來的部分就是表示符合 filterTable 規則、會被選取進來的 SOAP 封包。

對 XPath 有興趣者可參考 W3Schools 的說明 (http://www.w3schools.com/xml/xpath_intro.asp)

 

路由的動態更新 Dynamic Routing Service

什麼是路由的動態更新?所謂的路由動態更新是指,在 Routing Service 服務不需要重新啟動的情況下,透過程式碼動態更新 routing table,所以動態更新是可以在記憶體中發生,您可以在程式碼或是 Configuration 中指定動態更新路由所需要的組態,但,通常您可能需要一個啟動時的預設組態。

為了支援這樣需求,.NET Framework 針對路由服務提供 IExtension<ServiceHostBase>的介面,實作也就是 RoutingExtension 類別,所以要做到動態更新我們只需要呼叫 RoutingExtension.ApplyConfiguration() 就可讓路由服務組態在執行階段動態更新,非常的方便。

下面為 Dynamic Routing Service 動態路由更新的範例程式碼:

	RoutingConfiguration rc = new RoutingConfiguration();
	switch (destEndpoint)
	{
		case "VIP":
			ServiceEndpoint regularCalc = new ServiceEndpoint(
			ContractDescription.GetContract(typeof(IRequestReplyRouter)), new NetTcpBinding(),new EndpointAddress("net.tcp://localhost:9090/servicemodelsamples/service/"));
			rc.FilterTable.Add(new MatchAllMessageFilter(), new List<ServiceEndpoint> { regularCalc });
			serviceHost.Extensions.Find<RoutingExtension>().ApplyConfiguration(rc);
			Console.WriteLine("Applied new routing configuration.");
			break;
		case "NORMAL":
			ServiceEndpoint roundingCalc = new ServiceEndpoint(
			ContractDescription.GetContract(typeof(IRequestReplyRouter)),new NetTcpBinding(),new EndpointAddress("net.tcp://localhost:8080/servicemodelsamples/service/"));
			rc.FilterTable.Add(new MatchAllMessageFilter(), new List<ServiceEndpoint> { roundingCalc });
			serviceHost.Extensions.Find<RoutingExtension>().ApplyConfiguration(rc);
			Console.WriteLine("Applied new routing configuration.");
			break;
		default:
			Console.WriteLine("Incorrect value entered, no change.");
			break;
	}

 

新的組態會立即生效,但只會影響路由服務所處理的新的工作階段

 

常見的路由案例

常見的路由案例有以下:

  1. 服務版本控制:新舊交替、過渡期,往往必須維護舊版本,直到用戶端轉換至新服務為止
  2. 依據服務種類、流量分割:許多大型系統進行分散式運算皆會使用此類型,依據服務類型加以分類,將訊息轉送到指定服務端,或是根據客戶類型加以區分,轉送到指定服務端處裡
  3. 多點傳送:有時會需要將訊息同時送達多個服務端
  4. 動態更新:為了支援某些企業的重要的運作系統,訊息的處理過程不能有任何服務中斷,因此您必須能在執行階段內動態修改元件組態。

 

結語

結合 WCF 4.0 的所有功能大概都在前後這兩集文章裡了,或許部分內容有些艱深,因為前後這兩篇文章本來就是針對特定主題的參考書類型文章,您可能不會時常需要使用到,因為他也不是什麼熱門技術,但他可能許多熱門技術的關鍵基礎,當需要使用到時後,又會覺得書到用時方恨少XD


 

簽名:

學習是一趟奇妙的旅程

這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。

軟體開發之路(FB 社團)https://www.facebook.com/groups/361804473860062/

Gelis 程式設計訓練營(粉絲團)https://www.facebook.com/gelis.dev.learning/


 

如果文章對您有用,幫我點一下讚,或是點一下『我要推薦,這會讓我更有動力的為各位讀者撰寫下一篇文章。

非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^