在WCF中,我们可以给service contract指定callbackContract来进行回调, 而回调接口由客户端实现。为了说明问题,我们设计了一个简单的scenario。
scenario description:
假设WCF service提供简单的AddTo(),即进行累积。客户端通过proxy消费这个service并将计算结果发布到所有注册了回调通道的其他客户端。
回调接口设计如下:
<!-- <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);
}
服务接口如下:
public interface ICaculatorService
{
[OperationContract(IsOneWay=true)]
void AddTo(int n);
[OperationContract(IsOneWay
=true)]void Register();
}
服务类型设计如下:
<!-- <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.如下:
<!-- <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主程序如下:
<!-- <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回调及主程序如下:
<!-- <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如下:
总结:
事件发布/订阅模型有着广泛应用,比如实时任务调度,多人在线游戏,即时聊天,软件版本的自动更新等等。只有你想不到,没有你做不到:)
欲下载本文源代码,请点击此处