應用框架的設計與實現——.NET平臺(7.事件通知服務.源碼分析)


EventClient.cs

using System;
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;
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;
                }

            }

        }

    }

}

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章