可能是重复问题:
如何在ASP.NET MVC中正确处理404错误?
我按照 Asp.Net MVC(RC 5)中的404 Http错误处理程序 所述进行了更改,但仍然得到标准的404错误页面。我需要在IIS中做出一些更改吗?
可能是重复问题:
如何在ASP.NET MVC中正确处理404错误?
我按照 Asp.Net MVC(RC 5)中的404 Http错误处理程序 所述进行了更改,但仍然得到标准的404错误页面。我需要在IIS中做出一些更改吗?
我在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));
(可选)
说明:
我能想到6种情况,可以导致ASP.NET MVC3应用程序生成404错误。
由ASP.NET自动生成:
由ASP.NET MVC自动生成:
情况2:URL匹配一个路由,但指定的控制器不存在。
情况3:URL匹配一个路由,但指定的操作不存在。
手动生成:
情况4:操作使用方法HttpNotFound()返回一个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>
该解决方案存在问题:
尝试的解决方案:HTTP错误
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
这个解决方案存在问题:
尝试的解决方案: 使用HTTP错误替换
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404"/>
<error statusCode="404" path="App/Errors/NotFound" responseMode="ExecuteURL"/>
</httpErrors>
</system.webServer>
该解决方案存在以下问题:
尝试的解决方案:customErrors和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>
这个解决方案存在以下问题:
之前的人甚至尝试创建自己的库来处理此问题(请参见http://aboutcode.net/2011/02/26/handling-not-found-with-asp-net-mvc3.html),但是先前的解决方案似乎覆盖了所有情况,而不需要使用外部库的复杂性。
Response.Clear
存在什么问题?在博客文章中发表如此神秘的评论并得出“不要使用这种方法”的结论,然后在被要求澄清时保持沉默,这样做并没有什么帮助。 - Slauma另一种解决方案。
添加ErrorControllers或静态页面以显示404错误信息。
修改你的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>
这将处理未匹配到的路由和未匹配到的操作。
<customErrors mode="RemoteOnly">
可以查看实际的错误页面。 - Jakub Koneckireturn HttpNotFound();
作为ActionResult
使用,则无法正常工作。 - SlaumaMarco的回答是最好的解决方案。我需要控制我的错误处理,而且我是真的要全面控制它。当然,我稍微扩展了这个解决方案并创建了一个完整的错误管理系统来管理一切。我还在其他博客上阅读了这个解决方案,大多数高级开发人员似乎都认为它非常可行。
以下是我正在使用的最终代码:
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);
}
}
public void Fire404Error(HttpException exception)
{
//you can place any other error handling code here
throw new PageNotFoundException("page or resource");
}
现在,在我的Action中,我正在抛出一个我创建的自定义异常。我的控制器继承自我创建的自定义控制器基类。自定义基础控制器被创建用于覆盖错误处理。以下是我的自定义基础控制器类:
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);
}
}