ASP.NET MVC 404error handling
可能重复:
我怎样才能正确处理ASP.NET MVC中的404?
我已经在Asp.Net MVC(RC 5)中的404 Httperror handling程序进行了修改,我仍然得到标准的404错误页面。 我需要改变IIS中的东西吗?
又一个解决scheme。
添加ErrorControllers或静态页面以404错误信息。
修改你的web.config(在控制器的情况下)。
<customErrors mode="On" > <error statusCode="404" redirect="~/Errors/Error404" /> </customErrors>
或者在静态页面的情况下
<customErrors mode="On" > <error statusCode="404" redirect="~/Static404.html" /> </customErrors>
这将处理错过的路线和错过的行动。
我已经调查了如何在MVC (特别是MVC3)中正确pipe理404的很多 ,而这,恕我直言,是我提出的最好的解决scheme:
在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)); } } }
ErrorsController:
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),则应使用以下命令创build控制器:
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));
(可选的)
说明:
有6个场景,我可以想到ASP.NET MVC3应用程序可以生成404s的位置。
由ASP.NET生成:
- 场景1: URL与路由表中的路由不匹配。
由ASP.NET MVC生成:
-
场景2: URL匹配路由,但指定不存在的控制器。
-
场景3: URL匹配路由,但指定不存在的操作。
手动生成:
-
scheme4:一个操作通过使用方法HttpNotFound()返回一个HttpNotFoundResult。
-
场景5:一个动作抛出一个带有状态码404的HttpExceptionexception。
-
scheme6:一个操作手动将Response.StatusCode属性修改为404。
目标
-
(A)给用户显示一个自定义的404错误页面。
-
(B)维护客户端响应中的404状态码(对于search引擎优化尤为重要)。
-
(C)直接发送响应,不涉及302redirect。
解决scheme尝试:自定义错误
<system.web> <customErrors mode="On"> <error statusCode="404" redirect="~/Errors/NotFound"/> </customError> </system.web>
这个解决scheme的问题:
- 不符合情景(1),(4),(6)中的目标(A)。
- 不符合目标(B)自动。 必须手动编程。
- 不符合目标(C)。
解决scheme尝试:HTTP错误
<system.webServer> <httpErrors errorMode="Custom"> <remove statusCode="404"/> <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/> </httpErrors> </system.webServer>
这个解决scheme的问题:
- 只适用于IIS 7+。
- 不符合情景(2),(3),(5)中的目标(A)。
- 不符合目标(B)自动。 必须手动编程。
解决方法尝试:replaceHTTP错误
<system.webServer> <httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404"/> <error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/> </httpErrors> </system.webServer>
这个解决scheme的问题:
- 只适用于IIS 7+。
- 不符合目标(B)自动。 必须手动编程。
- 它掩盖了应用程序级别的httpexception。 例如不能使用customErrors部分,System.Web.Mvc.HandleErrorAttribute等,它不能只显示通用的错误页面。
解决方法尝试自定义错误和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>
这个解决scheme的问题:
- 只适用于IIS 7+。
- 不符合目标(B)自动。 必须手动编程。
- 不符合情景(2),(3),(5)中的目标(C)。
之前曾经困扰过这个问题的人甚至试图创build自己的库(参见http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html )。 但是,以前的解决scheme似乎涵盖了所有情况,没有使用外部库的复杂性。
Marco的回应是最好的解决scheme。 我需要控制我的error handling,我的意思是真的控制它。 当然,我已经扩展了这个解决scheme,创build了一个完整的错误pipe理系统来pipe理一切。 我也在其他博客上看过这个解决scheme,大多数高级开发人员似乎都非常接受。
这是我正在使用的最终代码:
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); } }
并在我的ErrorManagerController:
public void Fire404Error(HttpException exception) { //you can place any other error handling code here throw new PageNotFoundException("page or resource"); }
现在,在我的Action中,我抛出了一个我创build的自定义exception。 而我的控制器inheritance自我创build的一个自定义的基于Controller的类。 自定义基本控制器被创build来覆盖error handling。 这是我的自定义基本控制器类:
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的视图
我的解决scheme完美地工作,我能够处理我的网站上的任何错误,并显示不同的消息基于任何exceptiontypes。
看起来这是抓住一切的最好方法。
我怎样才能正确处理ASP.NET MVC中的404?
我可以推荐的是看FilterAttribute。 例如MVC已经有HandleErrorAttribute。 你可以自定义它来处理只有404。回复,如果你是分歧我会看看例子。
BTW
您在前面的问题中接受的解决scheme(包含最后一个路线)在很多情况下都不起作用。 HandleUnknownAction的第二个解决scheme将工作,但需要在每个控制器中进行此更改或具有单个基本控制器。
我的select是HandleUnknownAction的解决scheme。
在IIS中,您可以根据错误代码指定redirect到“特定”页面。 在你的例子中,你可以configuration404 – >你自定义的404错误页面。