zoukankan      html  css  js  c++  java
  • EsbAOP应用--异常关闭器

        以我自己的异常处理经验,我通常会在UI事件处理函数或线程启动函数中截获所有的异常,然后对截获的异常作特定的处理--很多情况下,是显示一个错误信息给用户,或记录异常日志!在这“很多情况下”,我都需要做相同的工作,首先是用try...catch把UI事件处理函数或线程启动函数中的所有代码围起来,然后,可能就是MessageBox.Show(ex.Message)或其它的处理。
        大家已经想到了,这类事情正好可以使用AOP来完成。本文将在前文介绍的EsbAOP的基础上来开发一个异常关闭器方面--ExceptionCloseerAspect,该方面修饰UI操作或修饰background线程的启动函数,用于控制是否拦截被修饰的方法抛出的异常,如果拦截,则对异常进行用户自定义处理,然后关闭该异常。
        关于ExceptionCloseerAspect要注意以下几个方面:
        (1)在UI操作时或后台线程中,经常其中会访问数据库或网络,为了截获这些异常,需要在每个UI的事件处理函数中写try...catch, 如果使用ExceptionCloseerAspect,则就不用在写try-catch了,ExceptionCloseerAspect会自动帮我们把异常截获,然后关闭它。
       (2)ExceptionCloseerAspect通常用于系统结构的最上层,比如UI层、或background线程的启动函数处。而且正好这些函数的返回值为void。
       (3)用户可以通过实现IExceptionHandler自定义异常处理方案,比如记录异常日志、弹出消息框通知使用者等。
       (4)注意,一般UI从Form继承,所以无法再从ContextBoundObject继承,也就无法对其使用Aspect,所以需要把最上层的逻辑封装在一个单独的类中==》而这有助于UI与逻辑的分离! 

        从前面的分析已经看到,线程有两种类型,一是主线程(通常为UI线程),一是后台线程,对于不同线程抛出的异常,用户可能需要作不同的处理,所以,我们使用枚举来定义线程类型:

        /// <summary>
        
    /// ExceptionCloseType 异常发生所在线程的类型
        
    /// </summary>
        public enum ExceptionHostType
        {
            NotSetted ,UIThread ,BackGroundThread
        }

        
        而为了使用户有机会处理抛出的异常,我们提供了IExceptionHandler接口:

        /// <summary>
        
    /// IExceptionHandler 在关闭异常之前,用户可以通过自定义的IExceptionHandler来处理异常,比如记录为日志或显示错误信息给用户
        
    /// </summary>
        public interface IExceptionHandler
        {
            
    void HandleException(Exception ee ,ExceptionHostType hostType) ;
        }


        在这些基础之上,我们就可以来实现ExceptionCloseerAspect了。从前文可以知道,ExceptionCloseerAspect只需要实现IAspect接口就可以了。现在给出其实现:

    public class ExceptionCloseerAspect :IAspect
        {
            
    public ExceptionCloseerAspect()
            {            
            }

            
    #region IAspect 成员
            
    public void PreProcess(IMethodCallMessage requestMsg, object aspectClassArgument, object aspectMethodArgument)
            {
                
            }

            
    public void PostProcess(IMethodCallMessage requestMsg, ref IMethodReturnMessage respond, object aspectClassArgument, object aspectMethodArgument)
            {            
                
    if(respond.Exception == null)
                {
                    
    return ;
                }

                Type HandlerType 
    = (Type)aspectClassArgument ;
                Type destType    
    = typeof(IExceptionHandler) ;
                
    if(! destType.IsAssignableFrom(HandlerType))
                {
                    
    return ;
                }

                IExceptionHandler exceptionHandler 
    = (IExceptionHandler)Activator.CreateInstance(HandlerType) ;
                
    if(aspectMethodArgument != null)
                {
                    exceptionHandler.HandleException(respond.Exception ,(ExceptionHostType)aspectMethodArgument) ;
                }
                
    else
                {
                    exceptionHandler.HandleException(respond.Exception ,ExceptionHostType.NotSetted) ;
                }

                
    //修改返回结果,关闭异常
                respond = new ReturnMessage(null ,requestMsg) ;
            }

            
    #endregion
        }


        上面的实现有几点需要说明:
    (1)ExceptionCloseerAspect的aspectClassArgument是实现了IExceptionHandler接口的类型
    (2)ExceptionCloseerAspect的aspectMethodArgument是ExceptionHostType枚举值之一。
    (3)注意PostProcess方法实现的最后一句,是AOP修改了方法调用的结果,从而关闭了异常。

        在实现了异常关闭器之后,我们就可以来小试牛刀了。首先,我们需要实现IAspectProcessorWrap接口来把ExceptionCloseerAspect所需要的资源反应出来:

    public class ExceptionClosserWrap :IAspectProcessorWrap
        {
            
    #region IAspectProcessorWrap 成员

            
    public Type AspectProcessorType
            {
                
    get
                {                
                    
    return typeof(ExceptionCloseerAspect);
                }
            }

            
    public object AspectClassArgument
            {
                
    get
                {
                    
    return typeof(ExceptionHandler) ;
                }
            }

            
    public EnterpriseServerBase.Aop.MultiAspect.AspectSwitcherState DefaultAspectSwitcherState
            {
                
    get
                {                
                    
    return AspectSwitcherState.On;
                }
            }

            
    #endregion
        }

        我们还需要实现IExceptionHandler来处理异常:

    public class ExceptionHandler :IExceptionHandler
        {
            
    #region IExceptionHandler 成员

            
    public void HandleException(Exception ee, ExceptionHostType hostType)
            {
                
    if(hostType == ExceptionHostType.UIThread)
                {
                    MessageBox.Show(ee.Message + "UI Thread !") ;
                }

                
    if(hostType == ExceptionHostType.NotSetted)
                {
                    MessageBox.Show(ee.Message 
    + " host thread not setted !") ;
                }

                
    if(hostType == ExceptionHostType.BackGroundThread)
                {
                    MessageBox.Show(ee.Message 
    + " background thread !") ;
                }
            }

            
    #endregion

        }

        前面的代码很容易明白,异常处理只是将异常信息显示给用户。现在来看看如何使用ExceptionCloseerAspect。需要再次强调的是,ExceptionCloseerAspect通常作用于UI事件处理函数或线程启动函数。我们已一个UI事件处理函数作为例子,首先要保证UI与业务逻辑分离,所以,我将业务逻辑封装在MyBusiness类中:

        [Aspect(typeof(ExceptionClosserWrap))]
        
    public class MyBusiness :ContextBoundObject
        {
            [AspectSwitcher(
    typeof(ExceptionClosserWrap) ,true ,ExceptionHostType.UIThread)]
            
    public void OnButton1Click()
            {
                
    throw new Exception("sky test exception !") ;
            }

            [AspectSwitcher(
    typeof(ExceptionClosserWrap) ,true)]
            
    public void OnButton2Click()
            {
                
    throw new Exception("sky2 test exception !") ;
            }

            [AspectSwitcher(
    typeof(ExceptionClosserWrap) ,true ,ExceptionHostType.BackGroundThread)]
            
    public void SkyThread()
            {
                
    throw new Exception("backGround thread exception !") ;
            }
        }

         而在所有的UI事件处理函数中,都将调用MyBusiness对应的方法,如:

    private void button1_Click(object sender, System.EventArgs e)
            {
                
    this.myBusiness.OnButton1Click() ;
            }

            
    private void button2_Click(object sender, System.EventArgs e)
            {
                
    this.myBusiness.OnButton2Click() ;
            }

            
    private void button3_Click(object sender, System.EventArgs e)
            {
                Thread thread 
    = new Thread(new ThreadStart(this.myBusiness.SkyThread)) ;
                thread.Start() ;
            }

         大家可以仿照上面的例子自己写一个,看看运行的结果,下面也给出示例源码下载!

        示例下载

  • 相关阅读:
    LeetCode 45 Jump Game II
    LeetCode 54. Spiral Matrix
    LeetCode 53. Maximum Subarray
    LeetCode 52. N-Queens II
    智齿的秘密
    《婚姻故事》观影笔记
    为什么在linux系统下安装anaconda的时候会报错
    pandas时间序列学习笔记
    极大似然估计和最小二乘法
    粗糙集学习笔记
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/245580.html
Copyright © 2011-2022 走看看