NET MVC 404错误处理

可能的复制品:
如何在 ASP.NET MVC 中正确处理404

我已经在 Asp.Net MVC (RC 5)中的404 Http 错误处理程序上做了修改,我仍然得到标准的404错误页面。我需要更改 IIS 中的某些内容吗?

166897 次浏览

在 IIS 中,可以根据错误代码指定重定向到“某个”页面。在您的示例中,可以配置404-> 自定义的404错误页面。

我可以推荐的是查看 FilterAttribute。例如,MVC 已经有 HandleErrorAttribute。您可以将其自定义为仅处理404。如果你感兴趣的话,我可以举个例子。

顺便说一句

在上一个问题中接受的解决方案(包括最后一条路线)在大多数情况下都不起作用。第二个解决方案与 处理未知行动将工作,但需要在每个控制器或有单一的基础控制器的变化。

我的选择是使用 HandleUnknown Action 的解决方案。

看起来这是捕捉一切的最好方法。

如何在 ASP.NET MVC 中正确处理404?

还有一个办法。

用404错误信息添加 ErrorController 或静态页。

修改 web.config (在使用控制器的情况下)。

<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Errors/Error404" />
</customErrors>
</system.web>

或者在静态页面的情况下

<system.web>
<customErrors mode="On" >
<error statusCode="404" redirect="~/Static404.html" />
</customErrors>
</system.web>

这将处理错过的路线和错过的行动。

我研究了 很多如何在 MVC (特别是 MVC3)中正确管理404,恕我直言,这是我想到的最好的解决方案:

在 global.asax:

public class MvcApplication : HttpApplication
{
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Response.Clear();


var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";


IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
}

错误控制器:

public sealed class ErrorsController : Controller
{
public ActionResult NotFound()
{
ActionResult result;


object model = Request.Url.PathAndQuery;


if (!Request.IsAjaxRequest())
result = View(model);
else
result = PartialView("_NotFound", model);


return result;
}
}

编辑:

如果你使用 IoC (例如 AutoFac) ,你应该使用以下方法创建你的控制器:

var rc = new RequestContext(new HttpContextWrapper(Context), rd);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Errors");
c.Execute(rc);

而不是

IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));

(可供选择)

说明:

我可以想到 ASP.NET MVC3应用程序可以生成404的6种情况。

由 ASP.NET 生成:

  • 场景1: URL 与路由表中的路由不匹配。

由 ASP.NET MVC 生成:

  • 场景2: URL 匹配一个路由,但指定了一个不存在的控制器。

  • 场景3: URL 匹配一个路由,但指定了一个不存在的操作。

手动生成:

  • 场景4: 一个操作通过使用方法 HttpNotFind ()返回一个 HttpNotFoundResult。

  • 场景5: 一个操作抛出一个状态代码为404的 HttpException 异常。

  • 场景6: 操作手动将 Response. StatusCode 属性修改为404。

目标

  • (A) 向用户显示一个自定义的404错误页面。

  • (B) 维护客户端响应的404状态码(对 SEO 特别重要)。

  • (C) 直接发送响应,不涉及302重定向。

解决方案尝试: 自定义错误

<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customErrors>
</system.web>

这个解决方案的问题是:

  • 不符合情景(1)、(4)、(6)中的目标(A)。
  • 不符合目标(B)自动。它必须手动编程。
  • 不符合目标(C)。

解决方案尝试: HTTP 错误

<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>

这个解决方案的问题是:

  • 只能在 IIS7 + 上工作。
  • 不符合情景(2)、(3)、(5)中的目标(A)。
  • 不符合目标(B)自动。它必须手动编程。

解决方案尝试: 使用替换的 HTTP 错误

<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>

这个解决方案的问题是:

  • 只能在 IIS7 + 上工作。
  • 不符合目标(B)自动。它必须手动编程。
  • 它掩盖了应用程序级别的 http 异常。例如,不能使用 customErrorssection,System。韦伯。MVC.HandleErrorAttribute 等。它不能只显示一般的错误页面。

解决方案尝试 customError 和 HTTP 错误

<system.web>
<customErrors mode="On">
<error statusCode="404" redirect="~/Errors/NotFound"/>
</customError>
</system.web>

还有

<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>

这个解决方案的问题是:

  • 只能在 IIS7 + 上工作。
  • 不符合目标(B)自动。它必须手动编程。
  • 不符合情景(2)、(3)、(5)中的目标(C)。

那些在创建自己的库之前就遇到这个问题的人(参见 http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html)。但是前面的解决方案似乎涵盖了所有场景,而没有使用外部库的复杂性。

马可的回应是最好的解决方案。我需要控制我的错误处理,我的意思是真正的 CONTROL 它。当然,我对解决方案进行了一些扩展,并创建了一个完整的错误管理系统来管理所有事情。我也在其他博客中读到过这个解决方案,它似乎被大多数高级开发人员所接受。

下面是我使用的最终代码:

protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
var exception = Server.GetLastError();
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "ErrorManager";
routeData.Values["action"] = "Fire404Error";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;


if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 404:
routeData.Values["action"] = "Fire404Error";
break;
}
}
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
IController errormanagerController = new ErrorManagerController();
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
var rc = new RequestContext(wrapper, routeData);
errormanagerController.Execute(rc);
}
}

在我的 ErrorManager 控制器中:

        public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}

现在,在我的操作中,我抛出了一个我已经创建的自定义异常。而且我的 Controller 继承自我创建的自定义 Controller Based 类。创建自定义基础控制器是为了重写错误处理。下面是我自定义的 Base Controller 类:

public class MyBasePageController : Controller
{
protected override void OnException(ExceptionContext filterContext)
{
filterContext.GetType();
filterContext.ExceptionHandled = true;
this.View("ErrorManager", filterContext).ExecuteResult(this.ControllerContext);
base.OnException(filterContext);
}
}

上面代码中的“ ErrorManager”只是一个使用基于 ExceptionContext 的 Model 的视图

我的解决方案工作完美,我能够处理我的网站上的任何错误,并显示基于任何异常类型的不同信息。