• 企业开发基础设施--事件通知服务(Remoting双向通信)


        事件通知服务用于解决多个应用程序之间的事件发布与预定的问题。在.NET平台上,跨应用程序的事件发布/预定通常以Remoting作为底层的通信基础,在此基础之上,事件通知服务使用中介者模式来简化跨应用程序的事件通知问题。
        本文采用的解决方案中,有两个重要组件:事件服务器EventServer和事件客户端EventClient。EventServer作为中介者,并作为一个独立的系统,通常可以将其作为windows服务运行。EventServer和EventClient之间的关系如下所示:
        
        每个需要事件通知的应用程序中,都包含了EventClient组件,应用程序通过EventClient与事件服务器进行交互,而当有事件发生时,EventClient也会触发相应的事件来通知应用程序。
        EventServer和EventClient实现了共同的接口IEventNotification:
        public interface IEventNotification
        {
            
    void SubscribeEvent(string eventName ,EventProcessHandler handler) ;//预定事件
            void UnSubscribeEvent(string eventName ,EventProcessHandler handler) ;//取消预定
            void RaiseEvent(string eventName ,object eventContent) ; //发布事件
        }

        
    public delegate void EventProcessHandler(string eventName ,object eventContent) ;
        注意,IEventNotification接口中的每个方法的第一个参数是事件名,事件名唯一标志了每个事件,它相当于一个主键。
        
        EventClient与包含它的应用程序之间的交互通过本地事件预定/发布来完成,而与EventServer之间的交互则通过remoting完成。其实现如下:    
        public class EventClient :MarshalByRefObject ,IEventNotification
        {
            
    private IEventNotification eventServer = null ;
            
    private Hashtable htableSubscribed       = new Hashtable() ; //eventName -- Delegate(是一个链表)

            
    public EventClient(string eventServerUri)
            {            
                TcpChannel theChannel 
    = new  TcpChannel(0) ;
                ChannelServices.RegisterChannel(theChannel) ;        
                
                
    this.eventServer = (IEventNotification)Activator.GetObject(typeof(IEventNotification) ,eventServerUri);
            }        

            public override object InitializeLifetimeService()
            {
                //Remoting对象 无限生存期
                return null;
            }

            
    #region IEventNotification 成员
            
    //handler是本地委托
            public void SubscribeEvent(string eventName, EventProcessHandler handler)
            {        
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;
                    
    if(handlerList == null)
                    {
                        
    this.htableSubscribed.Add(eventName ,handler) ;            
                        
    this.eventServer.SubscribeEvent(eventName ,new EventProcessHandler(this.OnRemoteEventHappen)) ;
                        
    return ;
                    }
                    
                    handlerList 
    = Delegate.Combine(handlerList ,handler) ;
                    
    this.htableSubscribed[eventName] = handlerList ;
                }
            }

            
    public void UnSubscribeEvent(string eventName, EventProcessHandler handler)
            {        
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;

                    
    if(handlerList != null)
                    {
                        handlerList 
    = Delegate.Remove(handlerList ,handler) ;
                        
    this.htableSubscribed[eventName] = handlerList ;
                    }
                }
            }

            
    public void RaiseEvent(string eventName, object eventContent)
            {    
                
    this.eventServer.RaiseEvent(eventName ,eventContent) ;
            }        
            
    #endregion

            
    #region OnRemoteEventHappen
            
    /// <summary>
            
    /// 当EventServer上有事件触发时,EventServer会转换为客户端,而EventClient变成远程对象,
            
    /// 该方法会被远程调用。所以必须为public
            
    /// </summary>        
            public void OnRemoteEventHappen(string eventName, object eventContent)
            {
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;
                    
    if(handlerList == null)
                    {
                        
    return ;
                    }
                
                    
    object[] args = {eventName ,eventContent} ;
                    
    foreach(Delegate dg in handlerList.GetInvocationList())
                    {
                        
    try
                        {                    
                            dg.DynamicInvoke(args) ;
                        }
                        
    catch(Exception ee)
                        {
                            ee 
    = ee ;
                        }
                    }
                }
            }
            
    #endregion
        }

         
        需要注意的是,EventClient从MarshalByRefObject继承,这是因为,当EventServer上有事件被触发时,也会通过Remoting Event来通知EventClient,这个时候,EventClient就是一个remoting object。另外,OnRemoteEventHappen方法必须为public,因为这个方法将会被EventServer远程调用。
        
        下面给出EventServer的实现:
        public class EventServer :MarshalByRefObject ,IEventNotification    
        {
            
    //htableSubscribed内部每项的Delegate链表中每一个委托都是透明代理
            private Hashtable htableSubscribed = new Hashtable() ; //eventName -- Delegate(是一个链表)
            public EventServer()
            {
            }

            public override object InitializeLifetimeService()
            {
                //Remoting对象 无限生存期
                return null;
            }


            
    #region IEventNotification 成员
            
    //handler是一个透明代理,指向EventClient.OnRemoteEventHappen委托
            public void SubscribeEvent(string eventName, EventProcessHandler handler)
            {            
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;

                    
    if(handlerList == null)
                    {
                        
    this.htableSubscribed.Add(eventName ,handler) ;                    
                        
    return ;
                    }
                    
                    handlerList 
    = Delegate.Combine(handlerList ,handler) ;
                    
    this.htableSubscribed[eventName] = handlerList ;
                }
            }

            
    public void UnSubscribeEvent(string eventName, EventProcessHandler handler)
            {            
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;

                    
    if(handlerList != null)
                    {
                        handlerList 
    = Delegate.Remove(handlerList ,handler) ;
                        
    this.htableSubscribed[eventName] = handlerList ;
                    }
                }
            }

            
    public void RaiseEvent(string eventName, object eventContent)
            {    
                
    lock(this)
                {
                    Delegate handlerList 
    = (Delegate)this.htableSubscribed[eventName] ;
                    
    if(handlerList == null)
                    {
                        
    return ;
                    }

                    
    object[] args = {eventName ,eventContent} ;
                    IEnumerator enumerator 
    = handlerList.GetInvocationList().GetEnumerator() ;
                    
    while(enumerator.MoveNext())
                    {
                        Delegate handler 
    = (Delegate)enumerator.Current ;
                        
    try
                        {
                            handler.DynamicInvoke(args) ;
                        }
                        
    catch(Exception ee) //也可重试
                        {
                            ee 
    = ee ;
                            handlerList 
    = Delegate.Remove(handlerList ,handler) ;
                            
    this.htableSubscribed[eventName] = handlerList ;
                        }
                    }
                }
            }

            
    #endregion
        }

        EventServer的实现是很容易理解的,需要注意的是RaiseEvent方法,该方法在while循环中对每个循环加入了try...catch,这是为了保证,当一个应用程序无法接收通知或接收通知失败时不会影响到其它的服务器。
        
        关于事件通知服务,可以总结为以下几点:
    (1)事件通知服务采用了中介者模式,所有的EventClient只与EventServer(中介者)交互,从EventServer处预定名为eventName的事件,或发布名为eventName的事件。
    (2)各个客户应用程序是对等的,它们都可以预定事件和发布事件。
    (3)EventServer不会自主地触发事件,它就像一个公共区(缓存预定者)或转发器(广播事件)。
    (4)EventServer 将在事件服务器上作为远程对象发布
    (5)客户应用程序将通过EventClient来预定事件、发布事件。

        最后,需要提出的是关于事件服务器的配置,需要将remoting的权限级别设置为FULL,否则,就会出现事件句柄无法序列化的异常。在我的示例中,EventServer的配置文件如下:

    <configuration> 
      
    <system.runtime.remoting> 
        
    <application> 
          
    <service> 
            
    <wellknown 
               
    mode="Singleton" 
               type
    ="EnterpriseServerBase.XFramework.EventNotification.EventServer,EnterpriseServerBase" 
               objectUri
    ="SerInfoRemote" /> 
          
    </service> 
          
    <channels> 
            
    <channel ref="tcp" port="8888">          
              
    <serverProviders> 
                
    <provider ref="wsdl" /> 
                
    <formatter ref="soap" typeFilterLevel="Full" /> 
                
    <formatter ref="binary" typeFilterLevel="Full" /> 
              
    </serverProviders> 
              
    <clientProviders>
               
    <formatter ref="binary" />
              
    </clientProviders>
            
    </channel> 
          
    </channels> 
        
    </application> 
      
    </system.runtime.remoting> 
    </configuration> 

        请特别注意,标志为红色的两句。 并且,在服务端程序启动时,配置Remoting:

      RemotingConfiguration.Configure("EventClient.exe.config");

       由于在服务端回调Client时,Client相对变成"Server",所以,Client也必须注册一个remoting通道。

    <system.runtime.remoting>
        
    <application>
          
    <channels>
            
    <channel ref="tcp" port="0">
              
    <clientProviders>
                
    <formatter ref="binary" />
              
    </clientProviders>
              
    <serverProviders>
                
    <formatter ref="binary" typeFilterLevel="Full" />
              
    </serverProviders>
            
    </channel>
          
    </channels>
        
    </application>
      
    </system.runtime.remoting>

       并且,在客户端程序启动时,配置Remoting:

      RemotingConfiguration.Configure("EventClient.exe.config");
        
      
    企业开发基础设施  主目录
  • 相关阅读:
    前段性能----详细渲染过程
    前段性能----repaint和reflow
    前段性能----缓存机制
    前段性能----带宽与延迟
    前端性能----从输入URL开始到返回数据的中间经历过程
    前端性能----TCP协议
    前端性能----CDN
    前端性能优化-学习链接,待持续更新
    前端性能----图像优化(图片)
    前端性能----静态资源,资源压缩
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/244318.html
Copyright © 2020-2023  润新知