一、应用场景

对于B/S应用程序,在部署到正式环境运行的过程中,很有可能出现一些在前期测试过程中没有发现的一些异常或者错误,或者说只有在特定条件满足时才会发生的一些异常,对于使用ASP.NET MVC开发的应用程序站点,在部署到IIS上后,如果开发人员未对程序进行错误处理,那么一旦程序出现未处理的错误或异常,用户将看到一个让人感到及其困惑的错误堆栈跟踪页面,使得站点的用户体验下降,从程序的角度上来说,不做自定义错误处理也不利于程序出问题时的根源查找,因为很多时候有些错误只在特定条件下满足时才重现,一旦错过,可能就需要花大量时间去测试来重现问题,如果此时开发人员有对程序中的运行时异常进行日志记录,那么或许将提供一些有价值的错误根源信息,下面我将向下大家讲解如何实现自定义异常处理并跳转到友好的错误提示页面。

二、异常处理&自定义错误页

1、通过异常过滤器 实现异常处理和自定义错误页

asp.net mvc 提供了 异常过滤器 的方式来实现当执行controller中某个action方法时抛出了未处理的异常时的捕捉,mvc中的异常过滤器是以特性(Attribute)的形式存在的,定义一个自定义异常过滤器只需要两个步骤:

1、定义一个类,继承FilterAttribute类,并实现IExceptionFilter接口 2、应用自定义异常过滤器至指定的 action方法 或 controller类 或 全局应用。

异常过滤器代码

using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Blog20180413.Filters
{
 public class CustomExceptionFilterAttribute : FilterAttribute, IExceptionFilter
 {
 //log4net组件,用于日志记录。
 static readonly ILog log = LogManager.GetLogger(typeof(CustomExceptionFilterAttribute));
 public void OnException(ExceptionContext filterContext)
 {
  //对捕获到的异常信息进行日志记录,方便开发人员排查问题。
  log.Error("应用程序异常", filterContext.Exception);

  //跳转到自定义的错误页,增强用户体验。
  ActionResult result = new ViewResult() { ViewName = "CustomErrorPage" };
  filterContext.Result = result;
  //异常处理结束后,一定要将ExceptionHandled设置为true,否则仍然会继续抛出错误。
  filterContext.ExceptionHandled = true;
 }
 }
}

使用异常过滤器

using Blog20180413.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Blog20180413.Controllers
{
 public class TestExceptionHandleController : Controller
 {
 [CustomExceptionFilter]
 public ActionResult Index()
 {
  string str = string.Empty;
  //将抛出转换异常
  int result = int.Parse(str);
  return View();
 }
 }
}

注意:

第二个步骤中提到,可以将自定义异常过滤器 只应用到 action或者controller,如果只想将指定的异常过滤器以特性的形式应用到指定的一个或者多个controller或者action,而不想应用到所有的controller或者action,那么必须将该异常过滤器继承FilterAttribute类,这是因为mvc框架是通过FilterAttributeFilterProvider.GetFilters来获取标记在指定controller或者action上的异常过滤器特性的,而GetFilters内部逻辑要求必须继承自FilterAttribute类。

如果需要将自定义的异常过滤器应用到所有的controller的action上,那么需要将该自定义异常过滤器注册到全局,代码如下:

using Blog20180413.Filters;
using System.Web;
using System.Web.Mvc;

namespace Blog20180413
{
 public class FilterConfig
 {
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
  filters.Add(new CustomExceptionFilterAttribute());
 }
 }
}

2、通过在Global.asax 中定义Application_Error方法 实现异常处理和自定义错误页

上面提到的 自定义异常过滤器只能捕获在执行action方法过程中抛出的异常(即使注册为全局过滤器也只能捕获action方法执行过程中抛出的异常),如果需要捕获更高级别的异常,也就是在请求执行过程中出现的任何异常(如在控制器的构造函数中抛出异常),那么可以使用该种方式,代码如下:

using log4net;
using log4net.Config;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Blog20180413
{
 public class MvcApplication : System.Web.HttpApplication
 {
  static readonly ILog log = LogManager.GetLogger(typeof(MvcApplication));
  protected void Application_Start()
  {
   AreaRegistration.RegisterAllAreas();
   FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
   RouteConfig.RegisterRoutes(RouteTable.Routes);
   XmlConfigurator.ConfigureAndWatch(new FileInfo(Server.MapPath("~/web.config")));
  }

  protected void Application_Error(object sender, EventArgs e)
  {
   Exception exception = Server.GetLastError();
   //Server.ClearError();
   //这里记录错误日志信息
   log.Error("MvcApplication 捕获异常", exception);
   //跳转到指定的自定义错误页
   Response.Redirect("/CustomErrorHandle/CustomErrorPage");
  }
 }
}

3、通过配置system.web->customErrors节点 实现自定义错误页

当你的站点发生异常时,如果你只是想简单的跳转到一个自定义错误页面,而不是对异常进一步处理时,那么你可以简单的作如下配置操作即可:

需要在web.config中做如下配置:

 <system.web>
  <customErrors mode="On" defaultRedirect="CustomErrorPage">
  </customErrors>
 </system.web>

注意:这里的CustomErrorPage是一个视图文件,放在Shared共享目录下。

如果你注册了HandleErrorAttribute异常过滤器到全局,那么在你的错误页中将能获取到和异常相关的一些信息。但此时配置到defaultRedirect的值的必须是Error

也就是自定义错误视图页面的名称必须为Error.cshtml,并且放在Shared目录,当然,你也可以通过在创建HandleErrorAttribute全局过滤器的过程中,设置器View属性,这样你就可以不用讲错误视图的名称设置为Error了.如下:

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
    HandleErrorAttribute errorAttribute = new HandleErrorAttribute();
    errorAttribute.View = "CustomErrorPage";
    filters.Add(errorAttribute);
 }

注册HandleErrorAttribute(使用默认的错误视图页面文件名)

public class FilterConfig
 {
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
   filters.Add(new HandleErrorAttribute());
  }
 }

定义Error.cshtml视图页

@{
 Layout = null;
}
@model HandleErrorInfo
<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width" />
 <title>Error</title>
</head>
<body>
 <div>
  @*通过HandleErrorAttribute异常过滤器捕获到的异常信息存储在Model属性中*@
  @Model.Exception.Message
 </div>
</body>
</html>

之所以通过注册HandleErrorAttribute过滤器捕获的异常在错误页中能获取异常信息可以看HandleErrorAttribute类的内部实现,发现加载错误视图页面的过程中,传递了一个HandleErrorInfo对象过去。

public virtual void OnException(ExceptionContext filterContext)
{
 if (filterContext == null)
 {
  throw new ArgumentNullException("filterContext");
 }
 if (!filterContext.IsChildAction && (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
 {
  Exception innerException = filterContext.Exception;
  if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))
  {
   string controllerName = (string) filterContext.RouteData.Values["controller"];
   string actionName = (string) filterContext.RouteData.Values["action"];
   HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
   ViewResult result = new ViewResult {
    ViewName = this.View,
    MasterName = this.Master,
    ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
    TempData = filterContext.Controller.TempData
   };
   filterContext.Result = result;
   filterContext.ExceptionHandled = true;
   filterContext.HttpContext.Response.Clear();
   filterContext.HttpContext.Response.StatusCode = 500;
   filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
  }
 }
}
public string View
{
 get
 {
  if (string.IsNullOrEmpty(this._view))
  {
   return "Error";
  }
  return this._view;
 }
 set => 
  (this._view = value);
}

三、总结

总的来说,Application_Error方法用于处理针对请求管道级别的发生的异常错误,而Mvc异常过滤器则只能处理在执行action方法过程中出现的异常.能处理的范围相对Application_Error较小,但在实际项目开发中,用Mvc异常过滤器处理异常相对会多一点,因为我们的功能业务往往体现在控制器的action方法执行的过程中,也就是在这个过程中较容易产生异常。故开发中用Mvc异常过滤器就能适应大部分的异常处理需求。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。