EventClient.cs
using System.Reflection;
using System.Collections;
using System.Threading;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using System.Runtime.Serialization;
using System.Runtime.Remoting.Activation;
namespace SAF.EventNotification
{
/// <summary>
/// EventClient 部署在客戶端
/// 因爲需要與服務端通信,必須是可序列化的,所以繼承自 MarshalByRefObject
/// </summary>
public class EventClient : MarshalByRefObject
{
public delegate void EventProcessingHandler(string eventName,object content);
public delegate void RepeaterHandler(string eventName, object content);
private EventServer es;
// 事件.{方法}
private Hashtable repeatDelegate= new Hashtable();
public EventClient(string url)
{
// 註冊一個雙向通信(端口號爲0)的信道
IDictionary props = new Hashtable();
props["port"] = 0;
BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
HttpChannel channel = new HttpChannel(props, clientProvider,null);
ChannelServices.RegisterChannel(channel);
// 獲取遠程代理類,遠程類必須是Singleton類型的,才能保證獲取的是同一個對象的代理
es = (EventServer)Activator.GetObject(typeof(EventServer),url);
}
/// <summary>
/// 增加一個方法的註冊
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="s">delegate on the client side that process the event notification</param>
public void SubscribeEvent(string eventName, EventProcessingHandler s)
{
try
{
// 檢查該事件是否已註冊過
Delegate handler =(Delegate)repeatDelegate[eventName];
// 如果事件註冊過,將新註冊的委託加入原有事件委託的列表中 Delegate.Combine(handler, s);
// hashtable 的事件委託重新指向新委託鏈
if (handler != null)
{
//chain up the delegates together
handler = Delegate.Combine(handler, s);
//reset the delegate object in the hashtable
repeatDelegate[eventName] = handler;
}
else
{
// 如果事件沒有註冊過,在hashtable中加入新的事件名及其委託
// 生成一個新的EventProcessingHandler委託 在服務端註冊
// 爲什麼使用新生成的委託對象註冊,而不用原有的委託來註冊??
// 個人認爲是其它對象沒有與服務端通信的信道,只有EventClient註冊過這樣的信道。
// 順帶着的好處是服務端不用按照事件註冊的方法數發通知,只需按照事件註冊的客戶數發通知即可。
repeatDelegate.Add(eventName,s);
EventClient.EventProcessingHandler repeat = new EventClient.EventProcessingHandler(Repeat);
//subscribe the "repeat" delegate to the EventServer.
es.SubscribeEvent(eventName,repeat);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// 撤銷一個方法的註冊
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="s">delegate on the client side that process the event notification</param>
public void UnSubscribeEvent(string eventName, EventProcessingHandler s)
{
// 取出相關事件的委託鏈
Delegate handler =(Delegate)repeatDelegate[eventName];
// 如果委託不爲空,撤銷該方法的註冊 Delegate.Remove(handler, s);
if (handler != null)
{
handler = Delegate.Remove(handler, s);
//reassign the chain back to the hashtable.
repeatDelegate[eventName] = handler;
}
}
/// <summary>
/// EventClient接到服務端的消息通知後的處理方法
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="content">the content of the notification</param>
public void Repeat(string eventName, object content)
{
// 從 hashtable 中取出事件的委託鏈
EventProcessingHandler eph = (EventProcessingHandler)repeatDelegate[eventName];
// 如果委託不爲空,向這些委託發送消息通知
if (eph !=null)
{
eph(eventName, content);
}
}
/// <summary>
/// 發佈一個事件的消息
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="content">event content</param>
public void RaiseEvent(string eventName, object content)
{
es.RaiseEvent(eventName,content);
}
}
}
EventServer.cs
using System.Collections;
using SAF.EventNotification;
namespace SAF.EventNotification
{
/// <summary>
/// EventServer 部署在服務端
/// </summary>
public class EventServer : MarshalByRefObject
{
// 事件.{客戶}
private Hashtable delegateMap =new Hashtable();
public EventServer()
{
}
/// <summary>
/// keep the EventServer live forever
/// </summary>
/// <returns></returns>
public override object InitializeLifetimeService()
{
//object live indefinitely
return null;
}
/// <summary>
/// 註冊一個客戶端事件
/// 類型是 EventClient.EventProcessingHandler
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="handler">client side delegate</param>
public void SubscribeEvent(string eventName, EventClient.EventProcessingHandler handler)
{
//ensure that only one thread modify the delegate chain at a time.
lock(this)
{
Delegate delegateChain = (Delegate)delegateMap[eventName];
// 檢查事件是否註冊過,如果沒有註冊過加入hashtable即可
if (delegateChain == null)
{
delegateMap.Add(eventName,handler);
}
else
{
// 如果事件註冊過,將委託加入事件的委託鏈中
delegateChain = Delegate.Combine(delegateChain, handler);
// 事件委託指向新委託鏈地址
delegateMap[eventName] = delegateChain;
}
}
}
/// <summary>
/// 撤銷註冊
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="handler"></param>
public void UnSubscribeEvent(string eventName, EventClient.EventProcessingHandler handler)
{
//ensure that only one thread modify the delegate chain at a time.
lock(this)
{
Delegate delegateChain = (Delegate)delegateMap[eventName];
// 事件委託存在的話,從委託鏈中刪除委託
if (delegateChain != null)
{
//remove the delegate from the chain
delegateChain = Delegate.Remove(delegateChain,handler);
// 將委託指針指向新的委託鏈
delegateMap[eventName] = delegateChain;
}
}
}
/// <summary>
/// 發佈消息
/// </summary>
/// <param name="eventName">event name</param>
/// <param name="content">content of the notification</param>
public void RaiseEvent(string eventName, object content)
{
Delegate delegateChain = (Delegate)delegateMap[eventName];
// 取得當前委託的鏈結構,不受後面的刪除操作影響
IEnumerator invocationEnumerator = delegateChain.GetInvocationList().GetEnumerator();
//loop through each delegate and invoke it.
while(invocationEnumerator.MoveNext())
{
Delegate handler = (Delegate)invocationEnumerator.Current;
try
{
handler.DynamicInvoke(new object[]{eventName,content}); // 發佈消息
}
catch (Exception ex)
{
// 產生異常時刪除當前委託,並且將事件委託鏈指向新委託鏈
delegateChain = Delegate.Remove(delegateChain, handler);
delegateMap[eventName] = delegateChain;
}
}
}
}
}