DotNet(C#)实现事件远程注册和触发
来源:互联网 发布:禁止软件联网win10 编辑:程序博客网 时间:2024/06/09 20:10
背景:
以前做过一套分布式任务管理架构来为某网站提供数据计算服务,
该网站每次数据计算可以分解为几百个小任务进行,而每个任务可能需要访问的数据量很大,
所以系统有一个管理平台,用来显示系统的运行状态,或某类计算节点的运行压力,
用户也可以在平台上执行一些管理功能,为了应对平台上频繁的功能追加,在系统核心模块
添加了事件处理模块,每当用户需要在平台添加某个功能,只需要开发对应功能的一个功能模块,
该功能模块只需要在事件处理注册一个事件,即可执行执行来自平台的命令需求。该模块可发布在
局域网内的任何一台机器上。
下面看代码, 临时写的,简化或省略了其中的数据部分,省略了系统定义的事件树,没有注释-_-!!
多个模块可重复注册同一种事件,如模块自检
先定义一个事件容器:
[Serializable] public class EventHandlerSet : IDisposable { protected System.Collections.Hashtable events = new System.Collections.Hashtable(); // indexer public virtual Delegate this[object eventKey] { get { return (Delegate)events[eventKey]; } set { events[eventKey] = value; } } public virtual void AddHandler(object eventKey, Delegate handler) { events[eventKey] = Delegate.Combine((Delegate)events[eventKey], handler); } public virtual void RemoveHandler(object eventKey) { events.Remove(eventKey); } public virtual void RemoveHandler(object eventKey, Delegate handler) { events[eventKey] = Delegate.Remove((Delegate)events[eventKey], handler); } // fire event public virtual void Fire(object eventKey, TaskEventArgs args) { if (!events.ContainsKey(eventKey)) { return; } Delegate handler = (Delegate)events[eventKey]; if (handler != null) { handler.DynamicInvoke(new object[] { eventKey, args }); } } // Synchronized public static EventHandlerSet Synchronized(EventHandlerSet eventHandlerSet) { if (eventHandlerSet == null) { throw new Exception(); } return new SynchronizedEventHandlerSet(eventHandlerSet); } public void Dispose() { events.Clear(); } }
线程安全:
public delegate void TaskEventHandler(TaskEventArgs args);[Serializable] public class SynchronizedEventHandlerSet : EventHandlerSet { private EventHandlerSet eventHandlerSet; public SynchronizedEventHandlerSet(EventHandlerSet eventHandlerSet) { this.eventHandlerSet = eventHandlerSet; Dispose(); } // indexer public override Delegate this[object eventKey] { [MethodImpl(MethodImplOptions.Synchronized)] get { return eventHandlerSet[eventKey]; } [MethodImpl(MethodImplOptions.Synchronized)] set { eventHandlerSet[eventKey] = value; } } [MethodImpl(MethodImplOptions.Synchronized)] public override void AddHandler(object eventKey, Delegate handler) { eventHandlerSet.AddHandler(eventKey, handler); } [MethodImpl(MethodImplOptions.Synchronized)] public override void RemoveHandler(object eventKey) { eventHandlerSet.RemoveHandler(eventKey); } [MethodImpl(MethodImplOptions.Synchronized)] public override void RemoveHandler(object eventKey, Delegate handler) { eventHandlerSet.RemoveHandler(eventKey, handler); } [MethodImpl(MethodImplOptions.Synchronized)] public override void Fire(object eventKey, TaskEventArgs args) { eventHandlerSet.Fire(eventKey, args); } [MethodImpl(MethodImplOptions.Synchronized)] public override void FireEx(object eventKey, TaskEventArgs args) { eventHandlerSet.FireEx(eventKey, args); } }
事件参数类:
[Serializable] public class TaskEventArgs : EventArgs { public object Args { get; set; } public TaskEventArgs() { } public TaskEventArgs(object args) { this.Args = args; } }
事件封送类,事件分为两类,定时触发(TimerEvent)和条件触发(CommandEvent):
public class EventProvider : MarshalByRefObject { private EventHandlerSet events = null; private TimerEventHandler timerHandler = null; private CommandEventHandler cmdHandler = null; private UnRegisterEventHandler unregisterHandler = null; public EventProvider() { events = EventHandlerSet.Synchronized(new EventHandlerSet()); } public void Fire(object key, TaskEventArgs args) { events.Fire(key, args); } #region Interface Method public void RegisterTimerEvent(string strName, int nInterval, object key, FireHandler fh) { events.AddHandler(key, fh); timerHandler(strName, nInterval, key); } public void RegisterCommandEvent(string strName, object key, FireHandler fh) { events.AddHandler(key, fh); cmdHandler(strName, key); } public void UnRegisterEvent(string strName, object key) { events.RemoveHandler(key); unregisterHandler(strName, key); } #endregion public override object InitializeLifetimeService() { return null; } #region Register Callback public void RegisterTimerEventHandler(TimerEventHandler teh) { timerHandler += teh; } public void RegisterCommandEventHandler(CommandEventHandler ceh) { cmdHandler += ceh; } public void RegisterUnRegisterEventHandler(UnRegisterEventHandler ueh) { unregisterHandler += ueh; } #endregion }
因为远程支持,添加事件封送的代理类,功能模块在此处注册事件:
/// <summary> /// 事件控制器实体代理类 /// Client端在此处注册事件,Fire函数委托给封送类触发 /// </summary> public class EventProviderWrapper : MarshalByRefObject { private EventHandlerSet events = null; private IRemotingClient client = null; private Dictionary<string, object> runtime = null; public EventProviderWrapper(int nPort) { events = EventHandlerSet.Synchronized(new EventHandlerSet()); runtime = new Dictionary<string, object>(); client = new RemotingProvider(nPort); client.ClientStart(); } public void Fire(object key, TaskEventArgs tea) { events.Fire(key, tea); } #region register event public void RegisterTimerEvent(string strName, int nInterval, TaskEventHandler teh) { if (runtime.ContainsKey(strName)) { return; } object key = CreateKey(); events.AddHandler(key, teh); runtime.Add(strName, key); client.RegisterTimerEvent(strName, nInterval, key, this.Fire); } public void RegisterCommandEvent(string strName, TaskEventHandler teh) { if (runtime.ContainsKey(strName)) { // 此事件已经注册 return; } object key = CreateKey(); events.AddHandler(key, teh); runtime.Add(strName, key); client.RegisterCommandEvent(strName, key, this.Fire); } public void UnRegisterEvent(string strName) { if (!runtime.ContainsKey(strName)) { // 此事件已经注册 return; } events.RemoveHandler(runtime[strName]); client.UnRegisterEvent(strName, runtime[strName]); runtime.Remove(strName); } public void Dispose() { foreach (string key in runtime.Keys) { events.RemoveHandler(runtime[key]); client.UnRegisterEvent(key, runtime[key]); } runtime.Clear(); } #endregion public override object InitializeLifetimeService() { return null; } private object CreateKey() { return Guid.NewGuid(); } }
Remoting处理,为了简化将Client和Server合到了一起:
public interface IRemotingClient { bool ClientStart(); void RegisterTimerEvent(string strName, int nInterval, object key, FireHandler fh); void RegisterCommandEvent(string strName, object key, FireHandler fh); void UnRegisterEvent(string strName, object key); } public interface IRemotingServer { bool ServerStart(TimerEventHandler teh, CommandEventHandler ceh, UnRegisterEventHandler ueh); bool Fire(object key, TaskEventArgs args); }public class RemotingProvider : IRemotingServer, IRemotingClient { private const string URL = "eventcontroller.soap"; private EventProvider provider = null; private string strIp = "localhost"; private int nPort = 0; public RemotingProvider(int port) { this.nPort = port; } public RemotingProvider(string ip, int port) : this(port) { this.strIp = ip; } #region IRemotingServer public bool ServerStart(TimerEventHandler teh, CommandEventHandler ceh, UnRegisterEventHandler ueh) { BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary prots = new Hashtable(); prots["name"] = "remoting"; prots["port"] = nPort; try { HttpChannel channel = new HttpChannel(prots, clientProvider, serverProvider); ChannelServices.RegisterChannel(channel); provider = new EventProvider(); provider.RegisterTimerEventHandler(teh); provider.RegisterCommandEventHandler(ceh); provider.RegisterUnRegisterEventHandler(ueh); ObjRef objRef = RemotingServices.Marshal(provider, URL); } catch { return false; } return true; } public bool Fire(object key, TaskEventArgs args) { try { provider.Fire(key, args); } catch { return false; } return true; } #endregion #region IRemotingClient public bool ClientStart() { BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); serverProvider.TypeFilterLevel = TypeFilterLevel.Full; IDictionary ports = new Hashtable(); ports["port"] = 0; HttpChannel channel = new HttpChannel(ports, clientProvider, serverProvider); try { ChannelServices.RegisterChannel(channel); } catch { } try { string strAddr = string.Format("http://{0}:{1}/{2}", strIp, nPort, URL); provider = (EventProvider)Activator.GetObject(typeof(EventProvider), strAddr); } catch { return false; } return true; } public void RegisterTimerEvent(string strName, int nInterval, object key, FireHandler fh) { provider.RegisterTimerEvent(strName, nInterval, key, fh); } public void RegisterCommandEvent(string strName, object key, FireHandler fh) { provider.RegisterCommandEvent(strName, key, fh); } public void UnRegisterEvent(string strName, object key) { provider.UnRegisterEvent(strName, key); } #endregion }
核心端事件管理类:
public class EventInfo : IDisposable { public object Key { get; private set; } public string Name { get; private set; } public int Interval { get; private set; } private Timer runTimer = null; private FireHandler fireHandler = null; public EventInfo(object key, string strName) { this.Key = key; this.Name = strName; } public EventInfo(object key, string strName, int nInterval, FireHandler fh) : this(key, strName) { this.Interval = nInterval; fireHandler += fh; runTimer = new Timer(); runTimer.Interval = nInterval; runTimer.Elapsed += new ElapsedEventHandler(runTimer_Elapsed); runTimer.Start(); } void runTimer_Elapsed(object sender, ElapsedEventArgs e) { TaskEventArgs args = new TaskEventArgs(); fireHandler(this.Key, args); } public void Dispose() { if (runTimer != null) { runTimer.Stop(); } } }
事件控制器:
public class EventController : IDisposable { private IRemotingServer server = null; public Dictionary<string, List<EventInfo>> listEvent = null; public EventController(int nPort) { listEvent = new Dictionary<string, List<EventInfo>>(); server = new RemotingProvider(nPort); server.ServerStart(this.OnRegisterTimerEvent, this.OnRegisterCommandEvent, this.OnUnRegisterEvent); } #region Inner Register #endregion #region Execute public void ExecuteCommand(IManagementMessage command) { if (!listEvent.ContainsKey(command.MessageCode)) { return; } List<EventInfo> listTmp = listEvent[command.MessageCode]; foreach (EventInfo item in listTmp) { TaskEventArgs args = new TaskEventArgs(command); server.Fire(item.Key, args); } } private void OnTimerFire(object key, TaskEventArgs e) { try { server.Fire(key, e); } catch { } } #endregion public void Dispose() { foreach (string strName in listEvent.Keys) { List<EventInfo> listTmp = listEvent[strName]; foreach (EventInfo item in listTmp) { item.Dispose(); } listTmp.Clear(); } listEvent.Clear(); } #region Component Register private void OnRegisterTimerEvent(string strName, int nInterval, object key) { EventInfo item = new EventInfo(key, strName, nInterval, this.OnTimerFire); List<EventInfo> listTmp = null; if (!listEvent.ContainsKey(strName)) { listTmp = new List<EventInfo>(); listTmp.Add(item); listEvent.Add(strName, listTmp); } else { listEvent[strName].Add(item); } } private void OnRegisterCommandEvent(string strName, object key) { EventInfo item = new EventInfo(key, strName); List<EventInfo> listTmp = null; if (!listEvent.ContainsKey(strName)) { listTmp = new List<EventInfo>(); listTmp.Add(item); listEvent.Add(strName, listTmp); } else { listEvent[strName].Add(item); } } private void OnUnRegisterEvent(string strName, object key) { if (!listEvent.ContainsKey(strName)) { return; } EventInfo item = listEvent[strName].Find( delegate(EventInfo ev) { return ev.Key == key; }); if (item == null) { return; } item.Dispose(); listEvent[strName].Remove(item); } #endregion }
功能端事件注册方法:
EventProviderWrapper wrapper = new EventProviderWrapper(nPort); // nPort为事件发布端口// Defines.CODE_SYSTEM_REPORT 为系统定义的事件Key, 非必需// 注册一个事件wrapper.RegisterCommandEvent(Defines.CODE_SYSTEM_REPORT, this.Invoke);
- DotNet(C#)实现事件远程注册和触发
- NodeJS:通过EventEmitter为对象注册和触发事件
- JQuery注册触发自定义事件
- 给回车键注册触发事件
- 事件的触发机制,定义,注册
- 事件触发机制:Poll,Select和Epoll实现原理分析
- linux和windows实现事件触发的通信方式
- 从一个bug说jquery的事件注册和触发机制
- jquery实现回车键触发事件
- jquery实现回车键触发事件
- jquery实现回车键触发事件
- 深入解析dotnet 事件和委托
- 多次注册事件会导致一个事件被触发多次
- javascript触发事件和说明
- C#_delegate和事件 - 如果金额小于0则触发事件
- 关于键盘触发事件和屏幕触发事件的问题
- 关于键盘触发事件和屏幕触发事件的问题
- jQuery事件触发和js手动触发事件
- Java程序员的未来发展之路
- 英语快照1---英语正能量
- 让Qt应用程序跑在Android上
- 针对安卓APP的 OCR图片识别技术研究与 DEMO
- talbe 奇偶行颜色变化
- DotNet(C#)实现事件远程注册和触发
- UIScrollView 滚动视图
- android SurfaceView详解
- 先序遍历,中序遍历的非递归方法
- struts1 实现 文件上传
- play framework2开发(六)
- 解决PHP生成校验码时“图像因其本身有错无法显示”的错误
- Flume NG 配置详解
- Rhythmbox 下中文的音乐文件显示成乱码解决办法