基于WCF的事件发布/订阅系统

在WCF中,我们可以给service contract指定callbackContract来进行回调, 而回调接口由客户端实现。为了说明问题,我们设计了一个简单的scenario。

scenario description:

假设WCF service提供简单的AddTo(),即进行累积。客户端通过proxy消费这个service并将计算结果发布到所有注册了回调通道的其他客户端。

回调接口设计如下:


<!-- <br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->[ServiceContract]
    
public   interface  ICaculatorCallBack
    {
        [OperationContract(IsOneWay 
=   true )]
        
void  Equals( int  result);
    }

服务接口如下:

<!-- <br /><br />Code highlighting 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();
    }

服务类型设计如下:

 


<!-- <br /><br />Code highlighting produced by Actipro CodeHighlighter (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服务的时候。 从AddTo implementation中我们可以看到:我们先将结算结果保存,并新建一个自定义事件,将计算结果保存至事件Args中,然后开始广播该事件 (BroadAddEvent)。广播该事件的作用就是让所有注册了该事件(即消费了Register服务)的客户端开始调用其事件处理程序 (CaculatorService_OnAddCompleted)。在该事件处理程序中,然后开始调用客户端的callbacb。

这就是整个利用callback机制进行广播的过程。

下面我们实现一个简单的客户端callback.如下:


<!-- <br /><br />Code highlighting produced by Actipro CodeHighlighter (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 Actipro CodeHighlighter (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 Actipro CodeHighlighter (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如下:

基于WCF的事件发布/订阅系统_第1张图片

 总结:

事件发布/订阅模型有着广泛应用,比如实时任务调度,多人在线游戏,即时聊天,软件版本的自动更新等等。只有你想不到,没有你做不到:)

欲下载本文源代码,请点击此处

你可能感兴趣的:(thread,游戏,应用服务器,LINQ,WCF)