在WCF中,我们可以给service contract指定callbackContract来进行回调, 而回调接口由客户端实现。为了说明问题,我们设计了一个简单的scenario。
scenario description:
假设WCF service提供简单的AddTo(),即进行累积。客户端通过proxy消费这个service并将计算结果发布到所有注册了回调通道的其他客户端。
回调接口设计如下:
Code
[ServiceContract]
public interface ICaculatorCallBack
{
[OperationContract(IsOneWay = true)]
void Equals(int result);
}
服务接口如下:
[ServiceContract(CallbackContract=typeof(ICaculatorCallBack),SessionMode=SessionMode.Required)]
public interface ICaculatorService
{
[OperationContract(IsOneWay=true)]
void AddTo(int n);
[OperationContract(IsOneWay=true)]
void Register();
}
服务类型设计如下:
Code
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服务的时候。 从AddTo implementation中我们可以看到:我们先将结算结果保存,并新建一个自定义事件,将计算结果保存至事件Args中,然后开始广播该事件(BroadAddEvent)。广播该事件的作用就是让所有注册了该事件(即消费了Register服务)的客户端开始调用其事件处理程序(CaculatorService_OnAddCompleted)。在该事件处理程序中,然后开始调用客户端的callbacb。
这就是整个利用callback机制进行广播的过程。
下面我们实现一个简单的客户端callback.如下:
Code
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
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
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如下:
总结:
事件发布/订阅模型有着广泛应用,比如实时任务调度,多人在线游戏,即时聊天,软件版本的自动更新等等。只有你想不到,没有你做不到:)
欲下载本文源代码,请点击此处
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· golang自带的死锁检测并非银弹
· 2024年终总结:5000 Star,10w 下载量,这是我交出的开源答卷
· 一个适用于 .NET 的开源整洁架构项目模板
· AI Editor 真的被惊到了
· API 风格选对了,文档写好了,项目就成功了一半!
· 【开源】C#上位机必备高效数据转换助手