【问题标题】:ASP.NET MVC 4 - Exception Handling Not WorkingASP.NET MVC 4 - 异常处理不起作用
【发布时间】:2012-12-12 17:29:09
【问题描述】:

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

基本的 [HandleError] 属性在 VS2012 中似乎不适用于针对 .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" 但这没有任何效果......共享的错误视图或我拥有的 CustomError 视图都没有被呈现。如果我更改 customErrors模式关闭,然后我可以按预期看到异常详细信息,所以它正确地抛出了“哦,有东西坏了”异常。

我还尝试将 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")]

任何帮助将不胜感激。如果您需要更多详细信息,请告诉我。

【问题讨论】:

    标签: asp.net-mvc exception-handling asp.net-mvc-4


    【解决方案1】:

    我还继续阅读 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");
        }
    }
    

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

      <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" />
    

    在定义的路由最后添加一条包罗万象的路由,以将 404 引导到自定义页面。

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

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

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

    【讨论】:

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

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

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

    【讨论】:

    • 尽管我没有在 web.config 中的任何地方使用RemoteOnly,但我的原始代码似乎可以远程运行,而不是本地运行!这对我来说非常令人惊讶。我确实必须在 web.config 的 &lt;system.webserver&gt; 部分添加 &lt;modules runAllManagedModulesForAllRequests="true" /&gt; 才能渲染视图,但这似乎很正常。这使得在本地调试变得更加困难,并且似乎是一个错误,因为 mode=RemoteOnly 没有被使用。如果有人知道如何让它在本地工作,请告诉我。 (我可能会为此专门提出第二个问题。)
    【解决方案3】:

    我遇到了类似的问题,并且在试图弄清楚发生了什么事情时迷失了方向。因此,以防万一其他人遇到类似的问题,这就是我的问题。

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

    @{ 布局=空; }

    【讨论】:

      【解决方案4】:

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

      defaultRedirect="Error"
      

      这明确定义了当抛出错误并且默认情况下没有在属性中指定视图时,MVC 应该将用户重定向到哪个视图。当然,这只有在 Error.cshtml 存在于 Shared 视图文件夹中时才有效。

      【讨论】:

      • 我终于开始尝试这些建议了。看起来使用 &lt;customErrors mode="On" defaultRedirect="Error" /&gt; 返回了我的 PageNotFound 错误页面,而不是来自共享错误视图的内容,并且 ViewData 中没有异常数据。我认为这是因为 /Error 实际上并不存在于服务器上,并且 web.config 对实际视图一无所知......但是当我修改 OnException 处理程序以也使用“错误”视图时,导致了我一直看到的相同的 HTTP 500 错误,并且我不再看到 PageNotFound 页面。 :(
      猜你喜欢
      • 2013-05-31
      • 2018-09-11
      • 1970-01-01
      • 2012-02-02
      • 1970-01-01
      • 2012-05-04
      • 2017-02-06
      • 2016-11-18
      • 1970-01-01
      相关资源
      最近更新 更多