天天看點

WF4工作流服務和雙工通信

雙工通信在很多時候都很有用,比如一個服務允許通知使用者目前的進度情況。一般情況下,我們可以使用WCF來實作,你可以通過使用指定CallbackContract的ServiceContract屬性的服務使用雙工,如伺服器端的代碼如下:

用戶端代碼如下:

但是這種方式并不适用于WF4中,因為WF4中沒有ServiceContract屬性,不能指定CallbackContract。然而WF4支援雙工通信。

代替正常WCF的雙工服務,工作流服務使用一種架構被稱作持久化雙工,這是一種更分離的方式來實作雙工通信,他的優點是通信的兩端都是獨立工作的,這也意味着一般的雙工通信的缺點在這裡不複存在。我們甚至可以在回調端使用一個完全不同于原始請求的綁定。不過作為用戶端有一個缺點就是必須建立自己的ServiceHost并且做為一個完整的WCF服務,比正常的雙工通信要複雜一些。下面我們看下如何實作。

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex1_2.png"></a>

第一步建立工作流服務,這個和其他的WCF工作流服務應用程式是一樣的,持久化的雙工需要一個上下文綁定,是以我們首先将綁定更改為wsHttpContextBinding如下:

下一步添加一個用戶端的控制台應用程式用來調用工作流服務,添加服務引用及如下代碼:

然後我們添加雙工部分,首先我們要在用戶端添加一個ServiceHost暴漏一個回調契約和回調服務定義,不像正常的雙工服務定義契約在服務端,我們需要在用戶端定義契約,代碼如下:

下一步宿主這個服務,代碼如下:

下一步是使工作流服務調用傳回給用戶端。 為此,我們需要做一些的事情。 首先,我們要讓工作流服務知道在哪裡可以回調。 這是通過将一個 CallbackContextMessageProperty 回調位址添加到請求标頭。

這可以通過使用一個 OperationContextScope 來替換proxy.GetDate() 實作,代碼如下:

然後我們更新工作流本身,首先我們先增加一個CorrelationHandle變量表示回調關聯。如下圖:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex2_2.png"></a>

下一步在GetData Receive活動的CorrelationInitializer中初始化callbackHandle,如下圖:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex3_2.png"></a>

下一步我們需要一個Send活動來發送響應給用戶端,設定其CorrelatesWith為之前初始化的callbackHandle,如下圖:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex4_2.png"></a>

最後我們設定Send活動屬性來比對用戶端的回調服務,如下:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex5_2.png"></a>

注意上面的設定中我們沒有設定AddressUri和EndpointAddress,因為他可以通過請求上下文和回調關聯句柄來提供,我們還設定了basicHttpBinding綁定,因為這個是用戶端使用的。

最後我們需要增加一個傳遞回來的消息,如下:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex6_2.png"></a>

都完成之後,我們可以運作服務端和用戶端,可以得到服務端的回調在用戶端上:

<a href="http://images.cnblogs.com/cnblogs_com/carysun/WindowsLiveWriter/WF4_88F7/duplex7_2.png"></a>

如果忘記設定回調CorrelationHandle會導緻用戶端得不到消息,會得到一個異常“Endpoint with Name='&lt;not specified&gt;' and ServiceContract '&lt;not specified&gt;' has a null or empty Uri property. A Uri for this Endpoint must be provided.”,這是由于Send活動找不到他的回調位址導緻。

不能從用戶端傳遞空的上下文,CallbackContextMessageProperty有幾個構造函數重載,一個隻有一個EndpointAddress參數,沒有上下文參數。看起來好像是一個很好的選擇我們可以不用指定任何的上下文資訊。不幸的是當Send活動嘗試尋找他的回調位址的時候會導緻ArgumentNullException異常,異常資訊為:"Value cannot be null. Parameter name: context".