ASP.NET MVC异常处理模块详解

2019-05-22 21:38:41王旭

  其中,add 节点用于增加具体的异常,它的 exception 属性是必须的,而view表示错误页,handler表示具体处理程序,如果view和handler都没有,异常将交给默认的HandleErrorAttribute处理。而group节点用于分组,例如上面的UserNameEmptyException和EmailEmptyException对应同一个处理程序和视图。

  程序会反射读取这个配置信息,并创建相应的对象。我们把这个配置文件放到Web.config中,保证它可以随时改随时生效。

2.2 异常信息包装对象

  这里我们定义一个实体对象,对应上面的节点。如下:

public class ExceptionConfig
{
  /// <summary>
  /// 视图
  /// </summary>
  public string View{get;set;}
 
  /// <summary>
  /// 异常对象
  /// </summary>
  public Exception Exception{get;set;}
 
  /// <summary>
  /// 异常处理程序
  /// </summary>
  public IExceptionHandler Handler{get;set;}
}

2.3 定义Handler接口

  上面我们说到,不同异常可能需要不同处理方式。这里我们设计一个接口如下:

public interface IExceptionHandler
{
  /// <summary>
  /// 异常是否处理完成
  /// </summary>
  bool HasHandled{get;set;}
 
  /// <summary>
  /// 处理异常
  /// </summary>
  /// <param name="ex"></param>
  void Handle(Exception ex);
}

  各种异常处理程序只要实现该接口即可。

2.3 实现IExceptionFilter

  这是必须的。如下,实现IExceptionFilter接口,SettingExceptionProvider会根据异常对象类型从配置信息(缓存)获取包装对象。

public class SettingHandleErrorFilter : IExceptionFilter
{
  public void OnException(ExceptionContext filterContext)
  {
    if(filterContext == null)
    {
      throw new ArgumentNullException("filterContext");
    }
    ExceptionConfig config = SettingExceptionProvider.Container[filterContext.Exception.GetType()];
    if(config == null)
    {
      return;
    }
    if(config.Handler != null)
    {
      //执行Handle方法        
      config.Handler.Handle(filterContext.Exception);
      if (config.Handler.HasHandled)
      {
        //异常已处理,不需要后续操作
        filterContext.ExceptionHandled = true;
        return;
      }
    }      
    //否则,如果有定制页面,则显示
    if(!string.IsNullOrEmpty(config.View))
    {
      //这里还可以扩展成实现IView的视图
      ViewResult view = new ViewResult();
      view.ViewName = config.View;
      filterContext.Result = view;
      filterContext.ExceptionHandled = true;
      return;
    }
    //否则将异常继续传递
  }
}

2.4 读取配置文件,创建异常信息包装对象

  这部分代码比较多,事实上,你只要知道它是在读取web.config的自定义配置节点即可。SettingExceptionProvider用于提供容器对象。