更新
由于此答案确实提供了解决方案,因此我不会对其进行编辑,但是我找到了一种解决此问题的更简洁的方法。有关详细信息,请参阅我的其他答案...
原始答案:
我弄清楚为什么Application_Error()
没有调用该方法......
全球.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()
方法。我找不到这方面的文档,但在programmers.stackexchange.com上的这个答案中有解释。
要为每个未处理的异常调用 ApplicationError() 方法,只需删除注册 HandleErrorAttribute 过滤器的行。
现在的问题是:如何配置 customErrors 以获得你想要的......
customErrors 部分默认为redirectMode="ResponseRedirect"
. 您也可以将 defaultRedirect 属性指定为 MVC 路由。我创建了一个非常简单的 ErrorController 并将我的 web.config 更改为如下所示...
网络配置
<customErrors mode="RemoteOnly" redirectMode="ResponseRedirect" defaultRedirect="~/Error">
<error statusCode="404" redirect="~/Error/PageNotFound" />
</customErrors>
此解决方案的问题在于,它会 302 重定向到您的错误 URL,然后这些页面以 200 状态代码响应。这导致谷歌将错误页面编入索引,这是不好的。它也不是很符合 HTTP 规范。我想做的不是重定向,而是用我的自定义错误视图覆盖原始响应。
我试图改变redirectMode="ResponseRewrite"
。不幸的是,这个选项不支持 MVC 路由,只支持静态 HTML 页面或 ASPX。我一开始尝试使用静态 HTML 页面,但响应代码仍然是 200,但至少它没有重定向。然后我从这个答案中得到了一个想法......
我决定放弃 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 模板共享任何标记,我不得不重写我们网站的标准页眉和页脚标记以获得一致的外观。
- *.aspx 页面可以通过点击其 URL 直接访问
这些问题有一些变通方法,但我对他们没有足够的关注来做任何额外的工作。
我希望这对大家有帮助!