ASP 百分网手机站

ASP.NET MVC异常处理模块简单教程-ASP.NET教程实例

时间:2018-02-15 15:38:27 ASP 我要投稿

ASP.NET MVC异常处理模块简单教程-ASP.NET教程实例推荐

  异常处理是每个系统必不可少的一个重要部分,它可以让我们的程序在发生错误时友好地提示、记录错误信息,更重要的是不破坏正常的数据和影响系统运行。

  在MVC中处理异常,相信开始很多人都是继承HandleErrorAttribute,然后重写OnException方法,加入自己的逻辑,例如将异常信息写入日志文件等。当然,这并没有任何不妥,但良好的设计应该是场景驱动的,是动态和可配置的。

  简单地说,不同的场景有不同的需求,而我们的.程序需要更好的面对变化。当然,继承HandleErrorAttribute也完全可以实现上面所说的,只不过这里我不打算去扩展它,而是重新编写一个模块,并且可以与原有的HandleErrorAttribute共同使用。

  下面让我们一起来学习ASP.NET MVC异常处理模块编程实例吧!

  2.1 定义配置信息

  从上面已经可以知道我们要做的事了,针对不同的异常,我们希望可以配置它的处理程序,错误页等。如下一个配置:

  <!--自定义异常配置-->

  <settingException>

  <exceptions>

  <!--add优先级高于group-->

  <add exception="Exceptions.PasswordErrorException"

  view ="PasswordErrorView"

  handler="ExceptionHandlers.PasswordErrorExceptionHandler"/>

  <groups>

  <!--group可以配置一种异常的view和handler-->

  <group view="EmptyErrorView" handler="ExceptionHandlers.EmptyExceptionHandler">

  <add exception="Exceptions.UserNameEmptyException"/>

  <add exception="Exceptions.EmailEmptyException"/>

  </group>

  </groups>

  </exceptions>

  </settingException>

  其中,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用于提供容器对象。

  public class SettingExceptionProvider

  {

  public static Dictionary<Type, ExceptionConfig> Container =

  new Dictionary<Type, ExceptionConfig>();

  static SettingExceptionProvider()

  {

  InitContainer();

  }

  //读取配置信息,初始化容器

  private static void InitContainer()

  {

  var section = WebConfigurationManager.GetSection("settingException") as SettingExceptionSection;

  if(section == null)

  {

  return;

  }

  InitFromGroups(section.Exceptions.Groups);

  InitFromAddCollection(section.Exceptions.AddCollection);

  }

  private static void InitFromGroups(GroupCollection groups)

  {

  foreach (var group in groups.Cast<GroupElement>())

  {

  ExceptionConfig config = new ExceptionConfig();

  config.View = group.View;

  config.Handler = CreateHandler(group.Handler);

  foreach(var item in group.AddCollection.Cast<AddElement>())

  {

  Exception ex = CreateException(item.Exception);

  config.Exception = ex;

  Container[ex.GetType()] = config;

  }

  }

  }

  private static void InitFromAddCollection(AddCollection collection)

  {

  foreach(var item in collection.Cast<AddElement>())

  {

  ExceptionConfig config = new ExceptionConfig();

  config.View = item.View;

  config.Handler = CreateHandler(item.Handler);

  config.Exception = CreateException(item.Exception);

  Container[config.Exception.GetType()] = config;

  }

  }

  //根据完全限定名创建IExceptionHandler对象

  private static IExceptionHandler CreateHandler(string fullName)

  {

  if(string.IsNullOrEmpty(fullName))

  {

  return null;

  }

  Type type = Type.GetType(fullName);

  return Activator.CreateInstance(type) as IExceptionHandler;

  }

  //根据完全限定名创建Exception对象

  private static Exception CreateException(string fullName)

  {

  if(string.IsNullOrEmpty(fullName))

  {

  return null;

  }

  Type type = Type.GetType(fullName);

  return Activator.CreateInstance(type) as Exception;

  }

  }

  以下是各个配置节点的信息:

  settingExceptions节点:

  /// <summary>

  /// settingExceptions节点

  /// </summary>

  public class SettingExceptionSection : ConfigurationSection

  {

  [ConfigurationProperty("exceptions",IsRequired=true)]

  public ExceptionsElement Exceptions

  {

  get

  {

  return (ExceptionsElement)base["exceptions"];

  }

  }

  }

  exceptions节点:

  /// <summary>

  /// exceptions节点

  /// </summary>

  public class ExceptionsElement : ConfigurationElement

  {

  private static readonly ConfigurationProperty _addProperty =

  new ConfigurationProperty("", typeof(AddCollection), null, ConfigurationPropertyOptions.IsDefaultCollection);

  [ConfigurationProperty("", IsDefaultCollection = true)]

  public AddCollection AddCollection

  {

  get

  {

  return (AddCollection)base[_addProperty];

  }

  }

  [ConfigurationProperty("groups")]

  public GroupCollection Groups

  {

  get

  {

  return (GroupCollection)base["groups"];

  }

  }

  }