我用的是RC2

使用URL路由:

routes.MapRoute(
    "Error",
     "{*url}",
     new { controller = "Errors", action = "NotFound" }  // 404s
);

上面似乎照顾到这样的请求(假设默认路由表由最初的MVC项目设置):"/blah/blah/blah/blah"

重写控制器本身的HandleUnknownAction():

// 404s - handle here (bad action requested
protected override void HandleUnknownAction(string actionName) {
    ViewData["actionName"] = actionName;
    View("NotFound").ExecuteResult(this.ControllerContext);
}  

但是,前面的策略不处理对坏/未知控制器的请求。例如,我没有“/IDoNotExist”,如果我请求这个,我从web服务器得到通用404页面,而不是我的404,如果我使用路由+覆盖。

最后,我的问题是:有没有办法在MVC框架中使用路由或其他东西来捕获这种类型的请求?

或者我应该默认使用Web。配置customErrors作为我的404处理程序,忘记这一切?我假设如果我使用customErrors,由于Web的原因,我将不得不在/Views之外存储通用404页面。配置直接访问限制。


当前回答

我对未处理区域、控制器和动作的简化解决方案:

Create a view 404.cshtml. Create a base class for your controllers: public class Controller : System.Web.Mvc.Controller { protected override void HandleUnknownAction(string actionName) { Http404().ExecuteResult(ControllerContext); } protected virtual ViewResult Http404() { Response.StatusCode = (int)HttpStatusCode.NotFound; return View("404"); } } Create a custom controller factory returning your base controller as a fallback: public class ControllerFactory : DefaultControllerFactory { protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { if (controllerType != null) return base.GetControllerInstance(requestContext, controllerType); return new Controller(); } } Add to Application_Start() the following line: ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));

其他回答

我浏览了所有的文章,但没有一篇对我有用: 我的要求用户键入任何在您的url自定义404页面应该显示。我认为它非常直截了当。但是你应该正确理解404的处理:

 <system.web>
    <customErrors mode="On" redirectMode="ResponseRewrite">
      <error statusCode="404" redirect="~/PageNotFound.aspx"/>
    </customErrors>
  </system.web>
<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/PageNotFound.html" responseMode="ExecuteURL"/>
    </httpErrors>
</system.webServer>

我发现这篇文章很有帮助。应该马上读。自定义错误页面- ben Foster

ASP。NET MVC不太支持自定义404页面。自定义控制器工厂,捕获所有路由,带有HandleUnknownAction的基控制器类-啊!

到目前为止,IIS自定义错误页面是更好的选择:

. config

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

ErrorController

public class ErrorController : Controller
{
    public ActionResult PageNotFound()
    {
        Response.StatusCode = 404;
        return View();
    }
}

示例项目

GitHub上的Test404 生活的网站

我真的很喜欢cottsaks的解决方案,认为它解释得非常清楚。我唯一增加的是修改步骤2如下

public abstract class MyController : Controller
{

    #region Http404 handling

    protected override void HandleUnknownAction(string actionName)
    {
        //if controller is ErrorController dont 'nest' exceptions
        if(this.GetType() != typeof(ErrorController))
        this.InvokeHttp404(HttpContext);
    }

    public ActionResult InvokeHttp404(HttpContextBase httpContext)
    {
        IController errorController = ObjectFactory.GetInstance<ErrorController>();
        var errorRoute = new RouteData();
        errorRoute.Values.Add("controller", "Error");
        errorRoute.Values.Add("action", "Http404");
        errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
        errorController.Execute(new RequestContext(
             httpContext, errorRoute));

        return new EmptyResult();
    }

    #endregion
}

基本上,这将阻止包含无效动作和控制器的url两次触发异常例程。Eg的url,如asdfsdf/dfgdfgd

因为我的评论太长了,所以发表了一个答案…

这既是对独角兽帖子/答案的评论,也是对它的问题:

https://stackoverflow.com/a/7499406/687549

比起其他答案,我更喜欢这个答案,因为它很简单,而且事实是,显然微软的一些人被咨询了。然而,我有三个问题,如果他们可以回答,那么我将把这个答案称为互联网上所有404/500个错误答案的圣杯。NET MVC (x)应用程序。

@Pure。Krome

Can you update your answer with the SEO stuff from the comments pointed out by GWB (there was never any mentioning of this in your answer) - <customErrors mode="On" redirectMode="ResponseRewrite"> and <httpErrors errorMode="Custom" existingResponse="Replace">? Can you ask your ASP.NET team friends if it is okay to do it like that - would be nice to have some confirmation - maybe it's a big no-no to change redirectMode and existingResponse in this way to be able to play nicely with SEO?! Can you add some clarification surrounding all that stuff (customErrors redirectMode="ResponseRewrite", customErrors redirectMode="ResponseRedirect", httpErrors errorMode="Custom" existingResponse="Replace", REMOVE customErrors COMPLETELY as someone suggested) after talking to your friends at Microsoft?

就像我说的;如果我们能让你的回答更完整就太好了,因为这似乎是一个相当受欢迎的问题,有54000 +的浏览量。

更新:Unicorn的答案是302 Found和200 OK,不能使用路由更改为只返回404。它必须是一个物理文件,不是很MVC:ish。我们来看另一个解。太糟糕了,因为这似乎是到目前为止的终极MVC:ish答案。

代码来自http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx,也可以在ASP.net MVC 1.0中使用

下面是我如何处理http异常:

protected void Application_Error(object sender, EventArgs e)
{
   Exception exception = Server.GetLastError();
   // Log the exception.

   ILogger logger = Container.Resolve<ILogger>();
   logger.Error(exception);

   Response.Clear();

   HttpException httpException = exception as HttpException;

   RouteData routeData = new RouteData();
   routeData.Values.Add("controller", "Error");

   if (httpException == null)
   {
       routeData.Values.Add("action", "Index");
   }
   else //It's an Http Exception, Let's handle it.
   {
       switch (httpException.GetHttpCode())
       {
          case 404:
              // Page not found.
              routeData.Values.Add("action", "HttpError404");
              break;
          case 500:
              // Server error.
              routeData.Values.Add("action", "HttpError500");
              break;

           // Here you can handle Views to other error codes.
           // I choose a General error template  
           default:
              routeData.Values.Add("action", "General");
              break;
      }
  }           

  // Pass exception details to the target error View.
  routeData.Values.Add("error", exception);

  // Clear the error on server.
  Server.ClearError();

  // Avoid IIS7 getting in the middle
  Response.TrySkipIisCustomErrors = true; 

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData));
}