ASP.NET MVC 5错误处理

39

我们希望处理403错误、404错误,所有由MySpecialDomainException引起的错误,并为所有其他错误(包括IIS配置中的错误!)提供默认错误页面。所有错误都应返回适当的Razor视图,最好在视图之前有一个ErrorController。例如:

public class ErrorController : Controller
{
    public ViewResult NotFound () { return View(); }
    public ViewResult Forbidden () { return View(); }
    public ViewResult Default ()
    {
        var ex = ObtainExceptionFromSomewhere();
        if(ex is MySpecialDomainException)
            return View("MySpecialDomainException", new ErrorModel { Exception = ex });

        return View("GeneralError", new ErrorModel { Exception = ex });
    }
}

目前在互联网上有多种不同的方法可以实现这一点,其中一些可能已经过时了。包括:

  • Controller.OnException()
  • 错误筛选器
  • web.config中的customErrors元素
  • 在Global.asax的Application_Error中处理

Q1: 在ASP.NET MVC 5中,推荐的方式是什么来满足我们的需求?

另外,我们想要捕捉在IIS主机中发生的错误。Q2:为了防止IIS必须处理任何404,我们考虑添加一个默认路由,匹配所有可能的URL - 这样做可行吗?最好是注册IIS' 404吗?

Q3:是否可能注册一个IIS错误页面并返回到控制器,或者IIS只能处理ASPX /静态HTML?


我很好奇...当IIS配置不正确时,你是如何提议使用Razor页面的?如果IIS无法正常工作,那么Razor也无法正常工作... - Erik Funkenbusch
是的,可能甚至不可能实现。也许我们只能在IIS上使用静态HTML。因此,最好使用ASP.NET MVC覆盖所有可能的URL,以防止404错误冒泡到IIS... - D.R.
http://www.codeproject.com/Articles/850062/Exception-handling-in-ASP-NET-MVC-methods-explaine - NoWar
2
https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging - GANI
@Liam提供的微软页面更适用于Web Forms而非MVC。 - Theophilus
3个回答

56

最好的方法是使用Global.Asax,因为您可以管理所有类型的错误(包括Ajax调用/所有意外错误)。使用其他方法无法实现。

像这样:

protected void Application_Error()
{
    HttpContext httpContext = HttpContext.Current;
    if (httpContext != null)
    {
        RequestContext requestContext = ((MvcHandler)httpContext.CurrentHandler).RequestContext;
        /* When the request is ajax the system can automatically handle a mistake with a JSON response. 
           Then overwrites the default response */
        if (requestContext.HttpContext.Request.IsAjaxRequest())
        {
            httpContext.Response.Clear();
            string controllerName = requestContext.RouteData.GetRequiredString("controller");
            IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
            IController controller = factory.CreateController(requestContext, controllerName);
            ControllerContext controllerContext = new ControllerContext(requestContext, (ControllerBase)controller);

            JsonResult jsonResult = new JsonResult
            {
                Data = new { success = false, serverError = "500" },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
            jsonResult.ExecuteResult(controllerContext);
            httpContext.Response.End();
        }
        else
        {
            httpContext.Response.Redirect("~/Error");
        }
    }
}

我该如何获取错误代码以作为动态传递到ServerError="500"或其他中? - Heemanshu Bhalla
当您的代码出现意外异常时,Application_Error会被处理,这意味着默认情况下您的响应结果将始终为500(内部服务器错误)。但是,如果您想更改错误代码,可以在代码中创建自定义异常,并根据您获得的错误异常设置所需的错误代码... - natnael88
为什么我的响应结果总是500?哦,我想我漏掉了一件事。只有在出现异常时才会调用Application_Error,而在404错误的情况下不会被调用。我认为最好使用web.config来处理404错误。 - Heemanshu Bhalla
1
抱歉,你是正确的。在MVC页面中,您可以管理所有意外错误,不仅仅是500(当然,如果您有代码异常,则始终为500(内部服务器错误))。这是代码:HttpException serverError = Server.GetLastError() as HttpException;如果(serverError!= null) { int errorCode = serverError.GetHttpCode(); } - natnael88
请注意,使用此解决方案,所有 AJAX 调用(包括调用不存在的端点)似乎都会成功。您需要解开响应数据以处理失败情况。 - StuartN

41

并不存在适用于所有应用的灵丹妙药。

你可以通过在web.config中使用httpErrors来显示友好的错误页面。与customErrors不同,这是一个IIS级别的设置,即使对于ASP.NET之外的错误,它也会为你显示友好的错误页面。

对于错误日志记录,我建议使用像ELMAH这样的HttpModule: https://code.google.com/p/elmah/

我写了一篇关于此的博客文章,在那里我解释了不同的错误处理方式: http://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging


1
第二段文字直接回答了问题:“您可以显示......”。相比之下,没有链接列表。只有两个链接——第一个是指向在ASP.NET中常用的错误日志记录工具的链接,第二个是指向详细的博客文章,更详细地介绍了这个主题,但比这里所问的还要多。我认为包含这些信息并没有什么坏处。谢谢你的回复。 - dustinmoris

7
更好的处理错误的方式是扩展handleerror属性。Handle error属性具有以下优点:
- 使用HandleErrorAttribute,我们可以更好地控制异常处理。HandleError使我们能够轻松地为不同的控制器和操作处理不同的错误,而在Application_Error中,要获得此功能,我们需要使用switch循环。 - 一旦进入Application_Error,您就已经退出了MVC,并且您将失去ControllerContext,然后我们不能做太多事情,这些事情很容易使用HandleError实现。 请参见以下文章,了解如何扩展错误处理属性及其优点: HandleError与Application_Error相比的优势

http://maheshde.blogspot.com.au/2012/09/error-handing-with-mvc-using-custom.html

http://www.codeproject.com/Articles/731913/Exception-Handling-in-MVC


谢谢您的分享,Mahesh!我在您的博客(https://maheshde.blogspot.com.au/2012/09/error-handing-with-mvc-using-custom.html?showComment=1511493570513)上留了评论。我想知道如何拦截500错误并在某些条件下将其重新打包为404错误。 - mattpm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接