MVC 中的异常处理






4.76/5 (74投票s)
MVC 逐步系列文章的支持性文章。在这里,我们将详细演示异常处理。
目录
引言
在本文中,我们将详细讨论 MVC 中的异常处理。如果您是 MVC 的新手,请阅读我们的 MVC 逐步文章的第一天。
实验室的初始设置
在开始异常处理的逐步演示之前,让我们创建一个示例。
本地级别异常处理
1. 简单的 Try…Catch 方法
public ActionResult TestMethod() { try { //.... return View(); } catch (Exception e) { //Handle Exception; return View("Error"); } }
局限性
上述方法的问题在于我们无法在多个操作方法中重用异常处理逻辑。这时就轮到我们的第二种方法了。2. 在控制器中重写 OnException 方法
protected override void OnException(ExceptionContext filterContext) { Exception e = filterContext.Exception; //Log Exception e filterContext.ExceptionHandled=true; filterContext.Result = new ViewResult() { ViewName = "Error" }; }
优势
现在我们可以在控制器中的所有操作之间共享错误处理逻辑。局限性
上述方法的问题在于我们无法在多个控制器之间重用异常处理逻辑。这时就轮到全局错误处理了。全局级别异常处理
步骤 1
在 Web.Config 中,只需按如下方式启用自定义错误并执行我们的应用程序。
<customerrors mode="On" />输出

似乎只有第一步完成了所有工作,但这是如何实现的?我们没有在任何地方指定错误页面(视图)名称,但当发生错误时,响应中仍然会出现错误视图。
让我们来理解一下这是如何发生的。
FilterConfig 类
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } }
如您所见,HandleErrorAttrubute 已添加到全局过滤器集合中。
RegisterGlobalFilters 方法在何处被调用?
在 Global.asax 文件中的 Application_Start 中,会调用 RegisterGlobalFilters 方法。

它有什么作用?
它会处理所有控制器中所有操作方法引发的所有异常,并返回共享文件夹中的错误视图。
控制器级别的 HandleError?
- 删除 FilterConfig 类中编写的代码。
- 将 HandleErrorAttribute 添加到控制器类,如下所示:

现在,TestingController 方法中所有操作方法引发的错误都将被处理。其他异常将被视为未处理的异常。
操作级别的 HandleError
将 HandleErrorAttribute 添加到操作方法,如下所示:

在错误视图中显示错误详情
为此,我们将使我们的错误视图成为 System.Web.Mvc.HandleErrorInfo 模型的强类型视图,然后像往常一样使用 @Model 关键字访问成员。其中一个成员是 Exception 对象。

不同异常的不同视图
为此,我们将使用 HandleErrorAttribute 构造函数的重载版本,如下所示:

HandleErrorAttribute 的局限性
- 错误不会被记录在任何地方。
- 控制器外部引发的异常将不会被处理。例如,由于无效 URL 而引发的异常将不会被处理。
- 无法根据场景进行异常处理。例如 - 当请求通过 ajax 发送时显示一个错误页面,当通过普通请求发送时显示另一个。
扩展 HandleErrorAttribute
上述某些局限性可以通过如下方式扩展默认的 HandleErrorAttribute 来克服。
private bool IsAjax(ExceptionContext filterContext) { return filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; } public override void OnException(ExceptionContext filterContext) { if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) { return; } // if the request is AJAX return JSON else view. if (IsAjax(filterContext)) { //Because its a exception raised after ajax invocation //Lets return Json filterContext.Result = new JsonResult(){Data=filterContext.Exception.Message, JsonRequestBehavior=JsonRequestBehavior.AllowGet}; filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.Clear(); } else { //Normal Exception //So let it handle by its default ways. base.OnException(filterContext); } // Write error logging code here if you wish. //if want to get different of the request //var currentController = (string)filterContext.RouteData.Values["controller"]; //var currentActionName = (string)filterContext.RouteData.Values["action"]; }
扩展 Handle Error Attribute 的优点
- 现在我们可以记录错误。
- 对异常处理有更多控制。现在我们对异常处理代码有完全的控制,因此我们可以简单地检查它是 Ajax 请求还是普通请求,并相应地进行处理。
“找不到资源”异常
这是 HandleErroAttribute 和 CustomHandleErrorAttribute 都无法处理的一种。
但我们可以遵循传统的 web.config 方法,如下所示:
<customerrors mode="On"> <error statuscode="404" redirect="~/Testing/NoPageFound"> </error></customerrors>
全局级别 HandleErrorAttribute 与 Application_Error 有何不同?
Application_Error 是一个应用程序级别的事件,我们在 global.asax 文件中定义它。当应用程序中发生未处理的异常时,它将被执行。
如果这是关键点,为什么我们不始终使用 Application_Error?
以下是 HandleError 相对于 Application_Error 的优点:
- 使用 HandleErrorAttribute,我们可以更精确地控制异常处理。HandleError 允许我们轻松地为不同的控制器和操作处理不同的错误,而在 Application_Error 中,要获得此功能,我们需要借助 switch 语句。
- 一旦进入 Application_Error,您就脱离了 MVC,并且会丢失 ControllerContext,因此您无法执行许多通过 HandleError 可以轻松完成的事情。
要学习 MVC,请从下面的 YouTube 视频开始,该视频教授 MVC 5,时长为 2 天,即 16 小时。
感谢阅读。希望您喜欢这篇文章。如果您对 MVC、WCF、设计模式、WPF、Angular.js、TFS、UML 或 BI 的任何技术培训感兴趣,请访问 www.sukesh-Marla.com 或联系 SukeshMarla@Gmail.com
在 .NET、C#、ASP.NET、SQL、WCF、WPF、WWF、SharePoint、设计模式、UML 等方面查看 600 多个常见问题解答。