在WCF中,我們可以給service contract指定callbackContract來進行回調, 而回調介面由用戶端實現。為了說明問題,我們設計了一個簡單的scenario。
scenario description:
假設WCF service提供簡單的AddTo(),即進行累積。用戶端通過proxy消費這個service並將計算結果發布到所有註冊了回調通道的其他用戶端。
回調介面設計如下:
Code
<!-- <br /><br />Code highlighting produced by ActiproCodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />-->[ServiceContract]
public interface ICaculatorCallBack
{
[OperationContract(IsOneWay = true)]
void Equals(int result);
}
服務介面如下:
<!-- <br /><br />Codehighlighting produced by Actipro CodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />-->[ServiceContract(CallbackContract=typeof(ICaculatorCallBack),SessionMode=SessionMode.Required)]
public interface ICaculatorService
{
[OperationContract(IsOneWay=true)]
void AddTo(int n);
[OperationContract(IsOneWay
=true)]
void Register();
}
服務類型設計如下:
Code
<!-- <br /><br />Code highlighting produced by ActiproCodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />-->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace WCFCallBack
{
public class AddEventAgrs : EventArgs
{
public int result;
}
[ServiceBehavior(InstanceContextMode
=InstanceContextMode.PerSession)]
class CaculatorService:ICaculatorService
{
public delegate void AddEventHandler(object sender, AddEventAgrs e);
public static event AddEventHandler OnAddCompleted;
public ICaculatorCallBack callback;
public int result;
public CaculatorService()
{
result = 0;
}
public void Register()
{
callback = System.ServiceModel.OperationContext.Current.GetCallbackChannel<ICaculatorCallBack>();
OnAddCompleted += new AddEventHandler(CaculatorService_OnAddCompleted);
}
void CaculatorService_OnAddCompleted(object sender, AddEventAgrs e)
{
Console.WriteLine("the OnAdd event has been triggered");
callback.Equals(e.result);
}
public void BroadAddEvent(AddEventAgrs e, AddEventHandler temp)
{
if (OnAddCompleted != null)
{
foreach (AddEventHandler handler in temp.GetInvocationList())
{
handler.BeginInvoke(this, e, null, null);
}
}
}
public void AddTo(int n)
{
AddEventAgrs e = new AddEventAgrs();
this.result += n;
e.result = result;
BroadAddEvent(e, OnAddCompleted);
}
}
}
回調介面和服務契約非常簡單,下面對serviceType作簡單說明:
關於AddEventHandler:
當用戶端調用AddTo這個服務的時候,伺服器端開始計算,當計算完畢之後,然後開始廣播並且調用各個用戶端的回調實現。為了捕獲計算完畢這個動作,因此我們必須定義一種類型的事件控制代碼並且申明相應類型的事件,因此本例中我們定義了一種AddEventHandle類型的事件OnAddCompleted
OnAddCompleted事件觸發的時機:
那麼OnAddCompleted事件是什麼時候觸發的呢?是在用戶端消費AddTo服務的時候。 從AddToimplementation中我們可以看到:我們先將結算結果儲存,並建立一個自訂事件,將計算結果儲存至事件Args中,然後開始廣播該事件(BroadAddEvent)。廣播該事件的作用就是讓所有註冊了該事件(即消費了Register服務)的用戶端開始調用其事件處理常式(CaculatorService_OnAddCompleted)。在該事件處理常式中,然後開始調用用戶端的callbacb。
這就是整個利用callback機制進行廣播的過程。
下面我們實現一個簡單的用戶端callback.如下:
Code
<!-- <br /><br />Code highlighting produced by ActiproCodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />-->class CallBack:ICaculatorServiceCallback
{
public void Equals(int n)
{
Console.WriteLine("this callback is implemented on client,the callback result is {0}", n.ToString());
}
}
用戶端1主程式如下:
Code
<!-- <br /><br />Code highlighting produced by ActiproCodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />-->using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WCFClient
{
class Program
{
static void showMenu()
{
Console.WriteLine("Operation MENU\n--------------------");
Console.Write("A:(Add) \nE:(exit):");
}
static void Main(string[] args)
{
try
{
showMenu();
System.ServiceModel.InstanceContext callbackInstance
= new System.ServiceModel.InstanceContext(new CallBack());
CaculatorServiceClient proxy = new CaculatorServiceClient(callbackInstance);
proxy.Open();
proxy.Register();
string answer = Console.ReadLine();
while (answer.ToUpper() != "E")
{
Console.Write("Please input the number to add:");
int n = Convert.ToInt16(Console.ReadLine());
proxy.AddTo(n);
System.Threading.Thread.Sleep(2000);
showMenu();
answer = Console.ReadLine();
}
proxy.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
}
用戶端2回調及主程式如下:
Code
<!-- <br /><br />Code highlighting produced by ActiproCodeHighlighter (freeware)<br/>http://www.CodeHighlighter.com/<br /><br />--> class CallBack:ICaculatorServiceCallback
{
public void Equals(int n)
{
Console.WriteLine("I have received a broadcasting news,the callback result is {0}", n.ToString());
}
}
class Program
{
static void Main(string[] args)
{
try
{
System.ServiceModel.InstanceContext callbackInstance = new System.ServiceModel.InstanceContext(new CallBack());
CaculatorServiceClient proxy = new CaculatorServiceClient(callbackInstance);
proxy.Open();
Console.WriteLine("I am another listener, and I am receiving all broadcasting news\n--------------------------------------------");
proxy.Register();
Console.ReadLine();
proxy.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}
運行screenshot如下:
總結:
事件發布/訂閱模型有著廣泛應用,比如即時任務調度,多人線上遊戲,即時聊天,軟體版本的自動更新等等。只有你想不到,沒有你做不到:)
欲下載本文原始碼,請點擊此處