我已在404 Http error handler in Asp.Net MVC (RC 5)处进行了更改,我仍然收到标准的404错误页面。我需要在IIS中更改某些内容吗?
答案 0 :(得分:358)
我已经研究了如何在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));
}
}
}
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),则应使用以下命令创建控制器:
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生成:
由ASP.NET MVC生成:
方案2:网址与路由匹配,但指定了不存在的控制器。
场景3:网址与路线匹配,但指定了不存在的操作。
手动生成:
场景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"/>
</customError>
</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>
此解决方案存在问题:
解决方案尝试自定义错误和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)。但是之前的解决方案似乎涵盖了所有场景,而没有使用外部库的复杂性。
答案 1 :(得分:140)
又一种解决方案。
将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>
这将处理错过的路线和错过的行动。
答案 2 :(得分:5)
Marco的回应是最佳解决方案。我需要控制我的错误处理,我的意思是真的控制它。当然,我已经扩展了一点解决方案并创建了一个管理所有内容的完整错误管理系统。我也在其他博客中读到了这个解决方案,大多数高级开发人员似乎都接受了这个解决方案。
以下是我使用的最终代码:
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中,我正在抛出我创建的自定义异常。我的Controller继承自我创建的自定义Controller Based类。创建自定义基本控制器以覆盖错误处理。这是我的自定义基本控制器类:
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的模型的视图
我的解决方案完美无缺,我可以在我的网站上处理任何错误,并根据任何异常类型显示不同的消息。
答案 3 :(得分:4)
看起来这是抓住一切的最好方法。
答案 4 :(得分:1)
在IIS中,您可以根据错误代码指定重定向到“特定”页面。在您的示例中,您可以配置404 - &gt;您自定义的404错误页面。
答案 5 :(得分:1)
我可以推荐的是查看FilterAttribute。例如,MVC已经有HandleErrorAttribute。您可以将其自定义为仅处理404.如果您是朋友,请回复我会看一下示例。
BTW
您在上一个问题中接受的解决方案(使用最后一条路线)在大多数情况下都不起作用。使用 HandleUnknownAction 的第二个解决方案可以工作,但需要在每个控制器中进行此更改或具有单个基本控制器。
我的选择是HandleUnknownAction的解决方案。