WCF 4.0 進階系列 – 第十六章 使用回調合約發布和訂閱事件(第二部分)


使用回調合約通知客戶端單向操作的結果

使用回調合約的原則是,提供一個服務,該服務采用單向操作—不返回任何信息—的方式通知客戶端程序。本小節的例子基於之前描述過的更改產品價格場景。當客戶端程序調用ProductsService服務的ChangePrice操作時,當數據庫中產品的價格更新后,服務將回調客戶端並通知客戶端價格已經發生變化。
 
練習:為ProductsService服務添加回調合約以及添加調用回調的操作
1. 使用Visual Studio,打開ProductsServiceV3.sln,該解決方案位於WCF\Step.by.Step\Solutions\Chapter16\ProductsServiceV3文件夾下。
該服務實現了ListProducts,GetProduct,CurrentStockLevel和ChangeStockLevelcaozuo .此外,它還包含了一個新的操作ChangePrice.客戶端程序可以調用該操作以更改產品的價格。此外,該解決方案包含了一個WPF程序寄宿該服務,一個客戶端程序用以測試ProdutsService服務。
2. 生成並運行該解決方案。在Products Service宿主窗口,點擊start按鈕。當服務啟動后,在客戶端控制台窗口中按下ENTER鍵。
客戶端程序連接到服務,首先顯示一個產品列表,然后顯示產品FR-M21S-40的詳細信息,並更改該產品的價格,最后顯示更新后的價格。
當客戶端程序結束后,關閉客戶端控制台窗口。在Products Service宿主窗口點擊Stop按鈕以停止服務,然后關閉宿主程序,最后返回到Visual Studio
3. 在解決方案窗口中,打開ProductsClient項目下的Programm.cs文件。
查看Main方法的代碼。該方法創建了Client類的一個實例,然后運行該實例的TestProductsService方法。TestProductsService方法創建代理對象,並使用該對象連接到ProductsService服務,然后執行ListPoructs操作和GetProduct操作。TestProductsService方法還調用PriceChange方法以更新指定產品的價格。ChangePrice操作在數據庫中產品的價格更新前會一直阻塞客戶端調用它,當產品價格更新后,該操作向調用者返回一個Boolean值以標明產品價格是否更新。由於該操作需要耗費一定的時間去更新數據庫,你將修改其為單向操作,並為ProductsService服務創建一個回調合約,使用該回調合約通知客戶端操作的結果。該策略可以使客戶端繼續運行而不需等待PriceChange操作的執行完成。
4. 在解決方案瀏覽器窗口,打開ProductsService服務下的IProductsService.cs文件。添加下面的回調合約:
該回調合約僅僅包含了一個操作OnPriceChanged。你將在后續步驟中更改ProductsService服務中的ChangePrice操作。該操作的目的是通知客戶端作為參數所傳入的產品的價格已經更改。請注意該操作指定為單向操作;它僅僅通知客戶端而且不返回其他任何響應。
5. 修改IProductsServiceV3接口的ServiceContract特性,使其引用第4步定義的回調合約
因為CallbackContract屬性必須為類型,所以上述代碼使用typeof操作返回IProductsServiceV3Callback接口的類型。
6. 在IProductsServiceV3接口中,修改ChangePrice操作的定義並標記該操作為單向操作。單向操作不能有返回值,所以更改返回類型為void
7. 打開ProductsService.cs文件,找到ChangePrice方法。該方法使用新的產品價格更新AdventureWorks數據庫,如果更新成功返回true,否則返回false。
更改該方法的返回類型為void。並修改return false或return true為return。
8. 生成ProductService項目
 
下面的步驟是在客戶都程序中實現回調合約,但首先你需要為客戶端生成代理類。
練習:生成客戶端代理對象並實現回調合約
1. 使用下面的步驟為客戶端程序生成代理類
1).打開Visual Studio命令行工具,並且切換路徑到Chapter16\ProductsServiceV3\ProductsService\bin\Debug目錄下
2).在Visual Studio命令行工具中,輸入下面的命令svcutil ProductsService.dll
3).然后執行下面的命令
Svcutil /namespace:*.ProductsClient.ProductsService *.wsdl *.xsd /out:ProductsServiceProxy.cs
2. 使Visual Studio命令行處於打開的狀態;然后回到Visual Studio。在ProductsClient項目中,刪除現存的ProductsServiceProxy.cs文件,然后添加剛生成的ProductsServiceProxy.cs文件到ProductsClient項目中。
3. 編輯ProductsClient項目下的Program.cs文件。修改Client類使其實現ProductsServiceCallback和IDisposable接口。
ProductsServiceCallback是代理對象中定義了回調合約的接口。所以Client類需要實現該接口。
4. 在Client列的TestProductsService方法后面添加OnPriceChanged方法
5. 在OnPriceChanged方法后,添加Dispose方法
6. 在TestProductsService方法中,修改創建Proxy對象的聲明:
上述代碼常見一個InstanceContext對象,該對象引用Client對象,並作為參數傳入到連接對象。請注意該連接所使用端點的名字發生了變化(現在使用WS2007HttpBinding_IProductsServiceV3);在后面的步驟中你將會在客戶端的配置文件中添加WS2007HttpBinding_IProductsServiceV3端點的定義。
7. 在TestProductsService方法中,找到if/else中調用proxy對象的ChangePrice方法的代碼片段。由於新的ChangePrice操作是單向操作,它不會返回任何值。更改這段代碼,並移除if/else過程。
8. 在catch代碼后,刪除關閉proxy對象的聲明;因為現在關閉proxy對象由Dispose方法來處理。
9. 在Programm.cs類的Main方法中,重構創建Client對象的生命,然后調用TestProductsService方法,並操作結束后等待用戶按下ENTER鍵結束程序。
10. 重新生成解決方案。
 
練習:配置WCF服務和客戶端程序使用WSDualHttpBinding綁定
1. 在ProductsServiceHost項目中,使用服務配置編輯器編輯App.config
2. 在配置面板,展開服務文件夾,展開Products.ProductsServiceImpl服務,展開端點文件夾,在WS2007HttpBinding_IProductsServcie端點上點擊右鍵,然后點擊刪除端點。在服務配置編輯器對話框中,點擊確認刪除。
3. 在配置面板,在端點文件夾上點擊右鍵,然后點擊創建新的服務端點。按照下表內容創建一個新的端點
屬性
名字 WSDualHttpEndpoint_IProductsService
地址 http://localhost:8010/ProductsService/Service.svc
綁定 wsDualHttpBinding
合約 Products.IProductsServiceV3
 
4. 保存配置文件,並退出WCF服務配置編輯器
5. 在ProductsServiceClient項目中,使用服務配置編輯器編輯App.config
6. 在配置面板,展開客戶端文件夾,右鍵點擊端點文件夾,然后點擊創建新端點以創建一個新的端點。按照下表內容設置新端點
屬性
名字
WSDualHttpEndpoint_IProductsService
地址
http://localhost:8010/ProductsService/Service.svc
綁定
wsDualHttpBinding
合約
ProductsClient.Products.IProductsServiceV3
 
與服務宿主程序不一樣,在客戶端你可以保留現有的客戶端端點。
7. 保存位置文件,並退出WCF服務配置編輯器。
8. 在非調適模式下啟動項目。在產品服務宿主窗口,點擊開始。然后再客戶端控制台窗口中,按下ENTER鍵。
客戶端程序首先顯示一份產品列表,然后電視FR-M21S-40產品的詳細信息,然后調用ChangePrice操作使該款產品的價格增加10美元。請注意在Test 3開始后,將顯示消息"Callback from service: Price of LL Mountain Frame – Sliver, 40 changed to $274.05"。該消息是由於服務調用OnPriceChanged操作而顯示。
 
 
 

使用回調合約實現事件機制

回調合約允許服務確認客戶端程序已經更改了產品的價格,但是接受確認消息的客戶端實例可能已經知道這點了,因為客戶端激發了更改價格的操作。無疑地,通知其他並發的客戶端程序價格已經改變是非常有用的。
你可以使用回調實現一個事件機制;服務發布事件並提供操作以供客戶端程序訂閱這些事件或取消訂閱。當時事件發生時,服務使用一個回調合約發送消息至每個訂閱了該事件的客戶端。為了實現這點,服務不惜必須引用每個客戶端實例。在下面的聯系中,你將修改ProdutsService服務以激活客戶端程序通過訂閱操作以關注感興趣產品的價格變化。該操作的目的是簡化緩存客戶端實例的引用,當服務調用OnPriceChanged操作之后將使用的這些客戶但實例。你還將添加一個取消訂閱操作以使客戶端程序可以取消價格更該訂閱。
練習:添加訂閱和卻笑訂閱操作至ProductsService服務
1. 在Visual Studio中,打開ProductsService項目下的IProductsService.cs文件。
2. 添加SubscribeToPriceChangedEvent時間和UnsubscribeToPriceChangedEvent事件到IProductsServiceV3服務合約中
客戶端程序將使用SubscribeToPriceChangedEvent操作關注感興趣產品的價格變化,使用UnsubscribeToPriceChangeEvent操作指明不再對產品價格變化感興趣。
3. 打開ProductsService.cs文件,添加下面的私有變量:
ProductsServiceImpl類針對每個對產品感興趣的客戶端實例,都把服務對其的客戶端回調引用添加到該列表中。
4. 添加SubscribeToPriceChangedEvent方法的具體實現
上述方法獲取調用ChangePrice操作並保存在訂閱列表中的的客戶端實例對應回調合約的引用。如果回調合約的引用已經在列表中存在,那么將不會把回調毀約的引用添加到該列表中。
5. 添加UnsubscribeToPriceChangedEvent方法的具體實現
上述方法從列表中移除調用ChangePrice操作的客戶端實例對於的回調引用。
6. 添加下面私有方法到ProductsServiceImple類中
該方法遍歷所有的訂閱列表中的所有回調引用。如果發現一個引用,並且該引用是有效的(客戶端程序實例仍然處於運行的狀態),該方法將調用OnPriceChanged操作,並將對應的產品作為參數傳遞給OnPriceChanged操作。如果引用是無效的,放方法則從訂閱列表中刪除該引用。
7. 在ChangePrice方法中,刪除獲取客戶端程序對應的回調引用的聲明,並刪除調用OnPriceChanged方法的代碼。取而代之的是,創建ProductData對象以保存修改產品的詳細信息,然后調用raisePriceChangeEvnet方法。
當客戶端程序實例更改了一個產品的價格,所有訂閱了價格更改時間的客戶端程序實例都會由於OnPriceChanged方法的執行而得到通知。
8. 重新生成ProductsService項目
 
練習:更新WCF客戶端程序以訂閱價格更改事件
1. 重新生成客戶端代理類
2. 關閉Visual Studio命令行工具窗口,然后返回到Visual Studio中。從ProductsClient項目中刪除ProductsServiceProxy.cs文件,並添加上一步生成的新版本的ProductsServiceProxy.cs文件
3. 打開ProductsClient項目的Programm.cs文件,添加調用SubscribeToPriceChangeEvent操作的代碼
無論何時,當客戶端程序實例更新一個產品的價格,服務將調用該客戶端實例的OnPriceChanged方法。
4. 重新生成ProductsClient項目。
 
練習:測試ProductsService服務的價格變更事件
1. 在解決方案瀏覽器窗口中,在ProductsServiceHost項目上點擊右鍵,選擇調適,然后點擊創建新的實例。在ProductsService寄宿窗口,點擊開始按鈕啟動服務。
2. 在Windows瀏覽器中,轉到\WCF\Step.by.Step\Solutions\Chapter16\ProductsServiceV3WithEvents\ProductsClient 文件夾下。
在該文件夾中,有一個名為RunClients的命令行文件。該命令文件簡單地實現了同時運行三次ProductsClient程序,每次都打開一個新的窗口;該文件的內容如下:
start bin\Debug\ProductsClient
start bin\Debug\ProductsClient
start bin\Debug\ProductsClient
3. 雙擊RunClients.cmd文件,將會出現三個控制台窗口,每個窗口都創建一個客戶端程序實例。在某一個控制台窗口中,按下ENTER鍵,等待出現產品列表,然后顯示FR-M21S-40產品的詳細信息,然后更改該款產品的價格。確認回調操作的消息出現。保持當前控制大窗口處於打開的狀態。
4. 在另外兩個控制台窗口中,按下ENTER鍵。等待出現產品列表,顯示FR-M21S-40產品的詳細信息,以及更改產品的價格。確認回調操作的消息出現。請注意,第二個回調操作的消息也出現在第一個控制台窗口中,不僅如此,第一個窗口中還顯示了由第二控制台窗口更新后的產品價格。
5. 在最后一個控制台窗口中,按下ENTER鍵。確認該客戶端實例更新了產品的價格並返回了回調消息。然后你可以發現第一個和第二個控制台窗口也輸出了回調消息。到現在為止,第一個控制台窗口顯示了三個回調消息。
6. 在每個控制台窗口中按下ENTER鍵以關閉客戶端程序。在ProductsService寄宿窗口中,點擊停止按鈕關閉服務,最后關閉ProductsService窗口。
 
發布和訂閱的傳送模型
使用回調合約可以非常容易地實現基於WCF的發布和訂閱服務。你應當意識到在前面的練習中一定程度上你所配置的環境是一個精心設置並且相對完美的運行環境。如果你在大型企業中,或者在Internetzhong實現這樣的一個系統,那么你應當考慮安全性和穩定性,此外還應考慮所選擇的模型對WCF服務回調客戶端程序所產生的影響。
一般地,實現發布和訂閱系統采用三種常見的模型,你可以基於任何一種模型構建WCF創建系統。每個模型都有其優缺點。
推送模型
該模型就是本章前面練習中你所使用的模型。在該模型中,發布者(WCF服務)通過回調合約中的操作直接向每個訂閱者(WCF客戶端程序)發送消息。服務必須有足夠的資源同時回調大量的訂閱者。在回調操作返回數據時服務需要對每一個訂閱者生成一個新線程、或者在回調操作不返回數據時使用單向操作方式進行回調。 這種方式的主要弱點在於安全性。服務調用客戶端的的回調操作可能被客戶端防火牆阻塞。
拖拉模型
使用這種模型,發布者在事件發生時更新唯一的且可信任的第三方服務的信息。 每個訂閱者周期地查詢第三方服務的信息是否已經更新。該模型減少了防火牆的問題,但是在訂閱者部分的要求更復雜。使用這個模型還可能會面臨擴展性方面的問題—當大量的訂閱者頻繁地查詢第三方服務。另外一個方面,入伙訂閱者不是經常地查詢第三方服務,那么客戶端可能錯過事件的發生。
中間人模型
該模型是前面兩種模型的結合。發布者在時間發生時更新唯一的且可信任的第三方服務。第三方服務放置於一個特定的位置,比如發不事件的服務和訂閱事件的客戶頓均信任的網絡中。訂閱者在第三方服務注冊事件,而不是直接在原始服務處訂閱事件。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM