问题 ASP.NET MVC 4 - 异常处理不起作用


当我的ASP.NET MVC 4应用程序发生错误时,我想根据错误类型为用户自定义视图。例如,找不到页面或发生异常(包含有关异常的一些用户友好的详细信息)。我已经检查了如何在StackOverflow和其他在线资源上执行此操作的其他示例,但没有一个答案对我有用。

VS2012中的基本[HandleError]属性似乎不适用于面向.NET 4.5的MVC 4应用程序。这是我家控制器中的代码:

[HandleError]
public ActionResult Index()
{
    Response.TrySkipIisCustomErrors = true; //doesn't work with or without this
    throw new NullReferenceException("Uh oh, something broke.");
}

它只是抛出异常,我希望由于[HandleError]属性而返回默认的〜/ Shared / Error.cshtml视图,但我得到的是HTTP 500内部服务器错误,表明该页面不能显示。我检查了我的web.config,不同的配置似乎表现得很奇怪。在该部分中,它目前包含:

<customErrors mode="On" />

(我已经尝试添加defaultRedirect并使用customErrors mode =“Off”但是没有任何效果...我正在渲染共享的Error视图或CustomError视图。如果我将customErrors模式更改为off ,然后我可以看到预期的异常细节,所以它正在抛出“呃哦,有点破坏”的例外。

我还尝试将一个OnException处理程序添加到HomeController,虽然我可以调试并看到正在引发OnException事件,但它没有任何区别:

protected override void OnException(ExceptionContext filterContext)
{
    base.OnException(filterContext);
    filterContext.ExceptionHandled = true;
    if (filterContext == null)
    {
        filterContext.Result = View("CustomError");
        return;
    }
    Exception e = filterContext.Exception;
    // TODO: Log the exception here
    ViewData["Exception"] = e; // pass the exception to the view
    filterContext.Result = View("CustomError");
}

我也尝试更改[HandleError]来指定一个视图,但这似乎也没有做任何事情:

[HandleError(View="CustomError")]

任何帮助将非常感激。如果您需要更多详细信息,请与我们联系。


13037
2017-12-12 17:29


起源



答案:


我似乎记得你必须从非本地主机IP地址(通常是另一台计算机)调用该页面。它必须是基于IIS的服务器,而不是内置的开发服务器(所以IIS或IIS Express,但是你必须配置IIS Express进行外部访问,这很痛苦)。

实际上,您可以调试它,您必须在调试计算机上配置本地服务器以接受外部请求,然后从远程服务器调用本地服务器。


4
2017-12-13 01:08



即使我没有使用 RemoteOnly 在web.config的任何地方,我的原始代码确实可以远程工作,只是不在本地!这对我来说非常令人惊讶。我确实要添加 <modules runAllManagedModulesForAllRequests="true" /> 在里面 <system.webserver> web.config的一部分,以便渲染视图,但这似乎很正常。这使得本地调试变得更加困难,而且从那时起就像是一个bug mode=RemoteOnly 没有被使用。如果有人发现如何让它在本地工作,请告诉我。 (我可以特别提出第二个问题。) - Robert Becker


答案:


我似乎记得你必须从非本地主机IP地址(通常是另一台计算机)调用该页面。它必须是基于IIS的服务器,而不是内置的开发服务器(所以IIS或IIS Express,但是你必须配置IIS Express进行外部访问,这很痛苦)。

实际上,您可以调试它,您必须在调试计算机上配置本地服务器以接受外部请求,然后从远程服务器调用本地服务器。


4
2017-12-13 01:08



即使我没有使用 RemoteOnly 在web.config的任何地方,我的原始代码确实可以远程工作,只是不在本地!这对我来说非常令人惊讶。我确实要添加 <modules runAllManagedModulesForAllRequests="true" /> 在里面 <system.webserver> web.config的一部分,以便渲染视图,但这似乎很正常。这使得本地调试变得更加困难,而且从那时起就像是一个bug mode=RemoteOnly 没有被使用。如果有人发现如何让它在本地工作,请告诉我。 (我可以特别提出第二个问题。) - Robert Becker


我还进行了无休止的阅读SO答案和各种博客帖子的尝试,试图让自定义错误页面起作用。以下是最终为我工作的内容。

第一步是使用IIS Express进行调试,而不是使用内置的Cassini Web服务器来“保证”调试体验将反映实时环境。

创建一个控制器来处理应用程序错误,并为您将处理的每个自定义错误添加一个操作。该操作应该执行任何日志记录,设置状态代码并返回视图。

public class ErrorsController : Controller
{
    // 404
    [HttpGet]
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        return View();
    }

    // I also have test actions so that I can verify it's working in production.
    [HttpGet]
    public ActionResult Throw404()
    {
        throw new HttpException((int)HttpStatusCode.NotFound, "demo");
    }
}

配置 customErrors web.config中的部分重定向到您的自定义错误操作。

  <system.web>
    <customErrors mode="RemoteOnly" defaultRedirect="Errors/InternalServerError">
      <error statusCode="400" redirect="Errors/BadRequest" />
      <error statusCode="403" redirect="Errors/Forbidden" />
      <error statusCode="404" redirect="Errors/NotFound" />
      <error statusCode="500" redirect="Errors/InternalServerError" />
    </customErrors>

添加 httpErrors 部分到 system.webServer 并在web.config中将errorMode设置为Detailed。为什么这对我来说是一个谜,但这是关键。

  <system.webServer>
    <httpErrors errorMode="Detailed" />

在最后定义的路线上添加一条catchall路线,将404s定向到自定义页面。

            // catchall for 404s
        routes.MapRoute(
            "Error",
            "{*url}",
            new {controller = "Errors", action = "NotFound"});

您可能还想创建自定义 HandleErrorAttribute 并将其注册为全局过滤器以记录500个错误。

这些步骤在开发(IIS Express)和生产(IIS7)环境中都适用于我。你需要改变 customErrors mode="On" 看看发展中的效果。


5
2017-12-12 18:45



我检查过,从项目属性> Web,它被默认为“使用本地IIS Web服务器”与IIS Express检查。我需要稍微检查一下其余部分。 - Robert Becker
在删除404的catch-all路由,修改web.config,创建ErrorsController,以及连接Errors / {Action}路由后,它似乎没有按预期工作。当这些状态代码出现时,就好像IIS服务器没有正确地重定向到错误/ <路径>。导航到<site> / Errors / <action>,可以正常工作,但是在设置时我没有获得自定义页面 Response.StatusCode。如果我删除了StatusCode,那么我确实得到了自定义页面,但它没有触发其他未找到的路径或异常(<site> / blah)。我已经在本地和远程进行了测试。 - Robert Becker
如果找到重定向不起作用的原因,那么这种方法可行(除非它可能无法将实际异常传递给InternalServerError视图以呈现自定义错误页面,如果需要) 。 - Robert Becker
自定义错误页面工作时需要发生错误,设置Response.StatusCode不会触发它们(也不会返回HttpNotFoundResult())。应用程序需要抛出异常,如我的ErrorsController中的Throw404操作所示。如果您需要解释错误并提供特定页面,请使用自定义HandleErrorAttribute来捕获500并重定向。 - Jamie Ide
这不起作用。最终错误网址仍然会发送状态代码200 OK - Matthew Lock


尝试将以下属性添加到 customErrors 标签:

defaultRedirect="Error"

这明确定义了MVC应该在抛出错误时重定向用户的视图,并且默认情况下不在属性中指定视图。这当然只会起作用 Error.cshtml 存在于 Shared views文件夹。


1
2017-12-12 18:35



我终于开始尝试这些建议了。它看起来像使用 <customErrors mode="On" defaultRedirect="Error" />返回我的PageNotFound错误页面而不是共享错误视图中的内容,并且ViewData中没有异常数据。我认为这是因为/ Error实际上并不存在于服务器上,并且web.config对实际视图一无所知...但是当我修改OnException处理程序以使用“错误”视图时,导致我一直看到的同样的HTTP 500错误,我不再看到PageNotFound页面。 :( - Robert Becker


我遇到了类似的问题,并且在某些时候试图弄清楚发生了什么。所以,万一其他人面临类似的问题,这就是我的问题所在。

错误页面试图使用我的_Layout页面。只需确保你的Error.cshtml页面有

@ {   Layout = null; }


1
2018-01-06 21:27