更新
由于此答案确实提供了解决方案,因此我不会对其进行编辑,但是我找到了一种更简洁的方法来解决此问题。详情见my other answer...
原答案:
我知道为什么没有调用 Application_Error() 方法...
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // this line is the culprit
}
...
}
默认情况下(生成新项目时),MVC 应用程序在Global.asax.cs 文件中有一些逻辑。此逻辑用于映射路由和注册过滤器。默认情况下,它只注册一个过滤器:HandleErrorAttribute 过滤器。当 customErrors 开启时(或者通过远程请求,当它设置为 RemoteOnly 时),HandleErrorAttribute 告诉 MVC 寻找错误视图并且它从不调用 Application_Error() 方法。我找不到这方面的文档,但在 this answer on programmers.stackexchange.com 中有说明。
要为每个未处理的异常调用 ApplicationError() 方法,只需删除注册 HandleErrorAttribute 过滤器的行。
现在的问题是:如何配置 customErrors 以获得你想要的...
customErrors 部分默认为redirectMode="ResponseRedirect"。您也可以将 defaultRedirect 属性指定为 MVC 路由。我创建了一个非常简单的 ErrorController 并将我的 web.config 更改为如下所示...
web.config
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
此解决方案的问题在于,它会执行 302 重定向到您的错误 URL,然后这些页面会以 200 状态代码响应。这导致谷歌将错误页面编入索引,这是不好的。它也不是很符合 HTTP 规范。我想做的不是重定向,而是用我的自定义错误视图覆盖原始响应。
我尝试更改redirectMode="ResponseRewrite"。不幸的是,this option does not support MVC routes,只有静态 HTML 页面或 ASPX。我一开始尝试使用静态 HTML 页面,但响应代码仍然是 200,但至少它没有重定向。然后我从this answer那里得到了一个想法……
我决定放弃 MVC 来处理错误。我创建了一个Error.aspx 和一个PageNotFound.aspx。这些页面非常简单,但它们有一种魔力......
<script type="text/C#" runat="server">
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Response.StatusCode = (int) System.Net.HttpStatusCode.InternalServerError;
}
</script>
这个块告诉页面提供正确的状态代码。当然,在 PageNotFound.aspx 页面上,我改用了HttpStatusCode.NotFound。我将 web.config 更改为如下所示...
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/PageNotFound.aspx" />
</customErrors>
一切都很完美!
总结:
- 删除线:
filters.Add(new HandleErrorAttribute());
- 使用
Application_Error()方法记录异常
- 使用带有 ResponseRewrite 的 customErrors,指向 ASPX 页面
- 让 ASPX 页面负责自己的响应状态代码
我注意到这个解决方案有几个缺点。
- ASPX 页面无法与 Razor 模板共享任何标记,我不得不重写我们网站的标准页眉和页脚标记以获得一致的外观。
- 可以通过点击 URL 直接访问 *.aspx 页面
这些问题有一些变通方法,但我对他们没有足够的关注来做任何额外的工作。
希望对大家有帮助!