65.9K
CodeProject 正在变化。 阅读更多。
Home

MVC 中的异常处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (74投票s)

2014年2月22日

CPOL

4分钟阅读

viewsIcon

344440

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?

  1. 删除 FilterConfig 类中编写的代码。
  2. 将 HandleErrorAttribute 添加到控制器类,如下所示:


现在,TestingController 方法中所有操作方法引发的错误都将被处理。其他异常将被视为未处理的异常。

操作级别的 HandleError

将 HandleErrorAttribute 添加到操作方法,如下所示:



在错误视图中显示错误详情

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



不同异常的不同视图

为此,我们将使用 HandleErrorAttribute 构造函数的重载版本,如下所示:



HandleErrorAttribute 的局限性

  1. 错误不会被记录在任何地方。
  2. 控制器外部引发的异常将不会被处理。例如,由于无效 URL 而引发的异常将不会被处理。
  3. 无法根据场景进行异常处理。例如 - 当请求通过 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 的优点

  1. 现在我们可以记录错误。
  2. 对异常处理有更多控制。现在我们对异常处理代码有完全的控制,因此我们可以简单地检查它是 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 的优点:

  1. 使用 HandleErrorAttribute,我们可以更精确地控制异常处理。HandleError 允许我们轻松地为不同的控制器和操作处理不同的错误,而在 Application_Error 中,要获得此功能,我们需要借助 switch 语句。
  2. 一旦进入 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 多个常见问题解答。

© . All rights reserved.