http-status-code-404 - ASP.NET MVC如何妥善处理404?

  显示原文与译文双语对照的内容

我刚刚开始使用 ASP.NET MVC,所以忍受我。 我已经搜索了这个站点和其他各种站点,并看到了一些实现。

编辑:我忘记提及我正在使用 RC2

使用网址路由:.


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

上面的请求似乎处理了这样的请求: "/blah/blah/blah/blah"

在控制器中 itself, 重写


//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.Config customErrors作为我的404处理程序,并忘记所有这些? 我假设如果使用 customErrors,就必须将通用 404页面存储在/Views 之外,因为直接访问的Web.Config 限制。 无论如何,任何最佳实践或者指导都是值得赞赏的。

时间:

代码取自 http://blogs.microsoft.co.il/blogs/shay/archive/1.0/real-world-error-hadnling-in-asp-net-mvc-rc2. aspx,并在 ASP.NET MVC中运行

下面是我处理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));
}

404的需求

以下是对 404解决方案的需求,下面我将展示如何实现它:

  • 我想处理带有错误动作的匹配路由
  • 我想处理带有坏控制器的匹配路由
  • 我想处理un-matched路由( 我的应用程序无法理解的任意 url ) - 我不想把这些冒泡到 Global.asax 或者 IIS,因为不能正确地重定向到我的MVC应用程序
  • 我想用与上面相同的方式来处理,自定义 404,比如当一个对象提交一个不存在的对象( 可能已经被删除) 时
  • 我想让我所有( 不是静态页面) @ # 404返回一个MVC视图的,以后可以给自己更多的数据,需要时( 好 404设计 ) 以及他们必须返回 HTTP 404状态码

解决方案

我认为你应该将 Application_Error 保存在 Global.asax 中,比如未处理的异常和日志( 就像的jacoby的答案一样),但不是 404处理。 这就是为什么我的建议将 404内容保存在 Global.asax 文件中。

步骤 1: 对 404 -error逻辑有一个共同的地方

这对于可维护性来说是一个好主意。 使用一个 ErrorController,以便改进未来到你精心设计 404页面容易,能够适应。 另外,确保你的响应的404代码为


public class ErrorController : MyController
{
 #region Http404

 public ActionResult Http404(string url)
 {
 Response.StatusCode = (int)HttpStatusCode.NotFound;
 var model = new NotFoundViewModel();
//If the url is relative ('NotFound' route) then replace with Requested path
 model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString!= url?
 Request.Url.OriginalString : url;
//Dont get the user stuck in a 'retry loop' by
//allowing the Referrer to be the same as the Request
 model.ReferrerUrl = Request.UrlReferrer!= null &&
 Request.UrlReferrer.OriginalString!= model.RequestedUrl?
 Request.UrlReferrer.OriginalString : null;

//TODO: insert ILogger here

 return View("NotFound", model);
 }
 public class NotFoundViewModel
 {
 public string RequestedUrl { get; set; }
 public string ReferrerUrl { get; set; }
 }

 #endregion
}

步骤 2: 使用基本控制器类,这样你就可以轻松地调用自定义 404操作并连接 HandleUnknownAction

在一系列 places, 404s ASP.NET MVC中需要 caught. 第一个是 HandleUnknownAction

ErrorController 和我们的新 Http404InvokeHttp404 方法创建一个公共的re-routing位置来操作。 认为 DRY


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
}

步骤 3: 在控制器工厂中使用依赖注入,并连接 404 HttpExceptions

像( 不必是 StructureMap ) 这样:

MVC1.0 示例:


public class StructureMapControllerFactory : DefaultControllerFactory
{
 protected override IController GetControllerInstance(Type controllerType)
 {
 try
 {
 if (controllerType == null)
 return base.GetControllerInstance(controllerType);
 }
 catch (HttpException ex)
 {
 if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
 {
 IController errorController = ObjectFactory.GetInstance<ErrorController>();
 ((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);

 return errorController;
 }
 else
 throw ex;
 }

 return ObjectFactory.GetInstance(controllerType) as Controller;
 }
}

MVC2.0 示例:


 protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
 {
 try
 {
 if (controllerType == null)
 return base.GetControllerInstance(requestContext, controllerType);
 }
 catch (HttpException ex)
 {
 if (ex.GetHttpCode() == 404)
 {
 IController errorController = ObjectFactory.GetInstance<ErrorController>();
 ((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);

 return errorController;
 }
 else
 throw ex;
 }

 return ObjectFactory.GetInstance(controllerType) as Controller;
 }

我认为最好是将错误更靠近它们起源的地方。 这就是为什么我喜欢上面的Application_Error 处理程序。

这是捕获 404的第二个位置。

步骤 4: 为无法解析到你的应用程序的url添加一个 Global.asax 路由到

这里路由应指向我们的Http404 操作。 注意,url 参数将是相对 url,因为路由引擎正在将域部分删除? 这就是我们在步骤 1中拥有所有条件url逻辑的原因。


 routes.MapRoute("NotFound","{*url}", 
 new { controller ="Error", action ="Http404" });

这是在你没有调用自己的MVC应用中捕获 404的第三个和最后一个地方。 如果你在这里没有捕捉到不匹配的路由,那么MVC会把问题传递到 ASP.NET ( global.asax ),你不会真的想这样做。

第 5步:最后,当你的应用程序无法找到某些东西时,调用 404

就像向我的贷款控制器( 从 MyController 派生) 提交错误标识时一样:


//
//GET:/Detail/ID

 public ActionResult Detail(int ID)
 {
 Loan loan = this._svc.GetLoans().WithID(ID);
 if (loan == null)
 return this.InvokeHttp404(HttpContext);
 else
 return View(loan);
 }

如果所有这些都能用更少的代码和更少的代码联系起来就好了,但是我认为这个解决方案更具可维护性,更易测试性和实用性。

感谢你的反馈到目前为止。 我希望得到更多。

注意:这编辑过了无明显与我原来的答案但目的/要求是相同的- 这就是为什么我没有添加了一个新答案

ASP.NET MVC不支持自定义 404页。 自定义控制器工厂,catch-all路由,带 HandleUnknownAction的基本控制器类- 辞退 !

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

web.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();
 }
}

项目示例

快速应答/tl ;DR

enter image description here

对于那些懒惰的人:


Install-Package MagicalUnicornMvcErrorToolkit -Version 1.0

然后从 global.asax 删除此行


GlobalFilters.Filters.Add(new HandleErrorAttribute());

,这只用于IIS7+和 IIS Express 。

如果你使用的是卡西尼。那名。 呃。呃。笨拙的 。。


长,解释的答案

我知道这已经被回答了。 但答案是非常简单的( 恭喜 David达米安爱德华兹 really ) 。

有 ,不需要做任何定制的 。

对于 ASP.NET MVC3,所有的Fragment和Fragment都在那里。

步骤 1 -> 在两个位置更新你的Web.Config 。


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


<system.webServer>
 <httpErrors errorMode="Custom">
 <remove statusCode="404" subStatusCode="-1"/>
 <error statusCode="404" path="/NotFound" responseMode="ExecuteURL"/>
 <remove statusCode="500" subStatusCode="-1"/>
 <error statusCode="500" path="/ServerError" responseMode="ExecuteURL"/>
 </httpErrors> 

...
<system.webServer>
...
</system.web>

现在仔细注意我决定使用的路线。 你可以使用任何东西,但我的路由是

  • /NotFound <- 找不到 404,错误页面。
  • /ServerError <- 对于任何其他错误,包括在我的代码中发生的错误。 这是 500内部服务器错误

仅在 <system.web> 中有一个自定义 entry, 看看第一部分如何? statusCode="404" 条目我只列出了一个状态代码,因为所有其他错误,包括 500 Server Error ( IE 。 当代码有 Bug 并使请求崩溃时发生的那些讨厌的错误。 所有其他错误都由设置 defaultRedirect="/ServerError" 处理。 然后,它说,如果你不是一个 404页面未找到,请转到 /ServerError的管线。

好了,这不碍事。 现在到 global.asax 中列出的路由

步骤 2 - 在 Global.asax 中创建路由

这是我的完整路线部分。


public static void RegisterRoutes(RouteCollection routes)
{
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});

 routes.MapRoute(
"Error - 404",
"NotFound",
 new { controller ="Error", action ="NotFound" }
 );

 routes.MapRoute(
"Error - 500",
"ServerError",
 new { controller ="Error", action ="ServerError"}
 );

 routes.MapRoute(
"Default",//Route name
"{controller}/{action}/{id}",//URL with parameters
 new {controller ="Home", action ="Index", id = UrlParameter.Optional}
 );
}

列出了两个忽略路由-> axd'sfavicons ( ooo ! 额外的忽略路由,为你然后( 顺序在这里是必不可少的),我有两个明确的错误处理路由。 后跟任何其他路由。 在这种情况下,默认的。 当然,我还有更多,但这对我的网站是特别的。 确定错误路由是否位于列表的顶部。 顺序是必需的。

最后,在 global.asax 文件内,我们不全局注册HandleError属性。 不,不,不,先生。Nadda 。 不。Nien 。负。noooooooooo 。。

global.asax 删除此行


GlobalFilters.Filters.Add(new HandleErrorAttribute());

步骤 3 - 使用动作方法创建控制器

现在,我们添加一个带有两个动作方法的控制器。。


public class ErrorController : Controller
{
 public ActionResult NotFound()
 {
 Response.StatusCode = (int)HttpStatusCode.NotFound;
 return View();
 }

 public ActionResult ServerError()
 {
 Response.StatusCode = (int)HttpStatusCode.InternalServerError;

//Todo: Pass the exception into the view model, which you can make.
//That's an exercise, dear reader, for -you-.
//In case u want to pass it to the view, if you're admin, etc.
//if (User.IsAdmin)//<-- I just made that up :) U get the idea...
//{
//var exception = Server.GetLastError();
////etc..
//}

 return View();
 }

//Shhh.. secret test method.. ooOOooOooOOOooohhhhhhhh
 public ActionResult ThrowError()
 {
 throw new NotImplementedException("Pew ^ Pew");
 }
}

好,我们来看看这个。 首先,上是没有 [HandleError] 属性在这里。 为什么因为 ASP.NET 中构建的框架已经处理错误和我们指定的所有我们需要做的,以处理错误:shit ) 就是在该方法? !

接下来,我有两个动作方法。 没什么难的。如果你想显示任何异常信息,那么你可以使用 Server.GetLastError() 获取该信息。

Bonus: 是,我做了第三个动作方法,来测试错误处理。

步骤 4 - 创建视图

最后,创建两个视图。 将它们放置在普通视图位置,用于这里控制器。

enter image description here

奖金注释

  • 你不需要一个 Application_Error(object sender, EventArgs e)
  • Elmah, 上面的步骤完全 100%它的所有工作 Elmah fraking wroxs !

我的朋友们,应该是。

现在,恭喜你阅读这么多,并拥有一个Unicorn作为奖励 !

enter image description here

采用,我已经调查了大量在MVC中如何正确地管理 404的日常 ( 特别 MVC3 ),和这个,恕我直言是最好的解决方法我已经走 up:

在 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;
 }
}

( 可选)

解释:

) 就我所知的,有 6不同情况下一些 ASP.NET MVC3应用可以生成 404 s 。

( 由 ASP.NET 框架自动生成:)

table,的管线中 ( 1 ) 是一个URL并没有找到一个匹配。

( 由 ASP.NET MVC框架自动生成:)

( 2 ) 一个网址在路由表中找到匹配项,但指定了一个不存在的控制器。

( 3 ) 是一个URL在路由表中找到匹配项,而指定一个non-existant作用。

( 手动生成:)

使用该方法 ( 4 ) 一个动作返回一个 HttpNotFoundResult by.

( 5 ) 一个操作抛出状态代码为 404的HttpException 。

( 6 ) 一个操作手动将 Response.StatusCode 属性修改为 404.

通常,你希望完成 3目标:

( 1 ) 演示一个自定义 404错误页面给用户。

在客户端响应 ( 2 ) 维持 code. 404状态

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

有几种方法可以尝试实现这一点:

( 1 )


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

这个解决方案的问题:

  1. 在情况下( 1 ),( 4 ),不符合客观
  2. 不符合目标( 2 ) 自动。 它必须手动编程。
  3. 不符合目标( 3 ) 。

( 2 )


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

这个解决方案的问题:

  1. 仅适用于 IIS 7 + 。
  2. 在情况下( 2 ),( 3 ),不符合客观
  3. 不符合目标( 2 ) 自动。 它必须手动编程。

( 3 )


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

这个解决方案的问题:

  1. 仅适用于 IIS 7 + 。
  2. 不符合目标( 2 ) 自动。 它必须手动编程。
  3. 它掩盖了应用程序级别的http异常。 比如 不能使用customErrors节,System.Web. mvc 。handleerrorattribute,等等 不仅可以显示一般错误页。

( 4 )


<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>

这个解决方案的问题:

  1. 仅适用于 IIS 7 + 。
  2. 不符合目标( 2 ) 自动。 它必须手动编程。
  3. 在情况下( 2 ),( 3 ),不符合客观

即使在试图创建自己的库( 参见 http://aboutcode.net/1 2011/02/26/handling-not-found-with-asp-net-mvc3. html ) 之前也会遇到问题的人。 但前面的解决方案似乎涵盖了所有没有使用外部库的复杂性。

我非常喜欢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两次触发异常例程。 例如 asdfsdf/dfgdfgd之类的url

让 @cottsak's 方法为无效控制器工作的唯一方法是修改CustomControllerFactory中现有的路由请求,如下所示:


public class CustomControllerFactory : DefaultControllerFactory
{
 protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
 {
 try
 {
 if (controllerType == null)
 return base.GetControllerInstance(requestContext, controllerType); 
 else
 return ObjectFactory.GetInstance(controllerType) as Controller;
 }
 catch (HttpException ex)
 {
 if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
 {
 requestContext.RouteData.Values["controller"] ="Error";
 requestContext.RouteData.Values["action"] ="Http404";
 requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);

 return ObjectFactory.GetInstance<ErrorController>();
 }
 else
 throw ex;
 }
 }
}

我应该提到我正在使用 MVC 2.0.

这是另一个方法使用MVC工具可供你处理请求不正确,所以控制器的名称,错误的路由名称,以及任何你认为合适的其他条件里面的一个动作方法。 我个人倾向于避免尽可能多的Web.Config 设置,因为它们执行 302/200 重定向,并且不支持使用 Razor 视图的ResponseRewrite ( Server.Transfer ) 。 我宁愿返回一个 404的自定义错误页面,原因是。

这其中有些是新的cottsak技术。

这个解决方案还使用了最小的Web.Config 设置,它支持 MVC 3错误过滤器。

用法

只需从操作或者自定义ActionFilterAttribute抛出 HttpException 。


Throw New HttpException(HttpStatusCode.NotFound,"[Custom Exception Message Here]")

步骤 1

将下列设置添加到 Web.Config 。 这是使用mvc的HandleErrorAttribute所必需的。


<customErrors mode="On" redirectMode="ResponseRedirect"/>

步骤 2

于 HTTP errors,相关添加自定义HandleHttpErrorAttribute类似于MVC框架,except: HandleErrorAttribute 。


<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Public Class HandleHttpErrorAttribute
 Inherits FilterAttribute
 Implements IExceptionFilter

 Private Const m_DefaultViewFormat As String ="ErrorHttp{0}"

 Private m_HttpCode As HttpStatusCode
 Private m_Master As String
 Private m_View As String

 Public Property HttpCode As HttpStatusCode
 Get
 If m_HttpCode = 0 Then
 Return HttpStatusCode.NotFound
 End If
 Return m_HttpCode
 End Get
 Set(value As HttpStatusCode)
 m_HttpCode = value
 End Set
 End Property

 Public Property Master As String
 Get
 Return If(m_Master, String.Empty)
 End Get
 Set(value As String)
 m_Master = value
 End Set
 End Property

 Public Property View As String
 Get
 If String.IsNullOrEmpty(m_View) Then
 Return String.Format(m_DefaultViewFormat, Me.HttpCode)
 End If
 Return m_View
 End Get
 Set(value As String)
 m_View = value
 End Set
 End Property

 Public Sub OnException(filterContext As System.Web.Mvc.ExceptionContext) Implements System.Web.Mvc.IExceptionFilter.OnException
 If filterContext Is Nothing Then Throw New ArgumentException("filterContext")

 If filterContext.IsChildAction Then
 Return
 End If

 If filterContext.ExceptionHandled OrElse Not filterContext.HttpContext.IsCustomErrorEnabled Then
 Return
 End If

 Dim ex As HttpException = TryCast(filterContext.Exception, HttpException)
 If ex Is Nothing OrElse ex.GetHttpCode = HttpStatusCode.InternalServerError Then
 Return
 End If

 If ex.GetHttpCode <> Me.HttpCode Then
 Return
 End If

 Dim controllerName As String = filterContext.RouteData.Values("controller")
 Dim actionName As String = filterContext.RouteData.Values("action")
 Dim model As New HandleErrorInfo(filterContext.Exception, controllerName, actionName)

 filterContext.Result = New ViewResult With {
. ViewName = Me.View,
. MasterName = Me.Master,
. ViewData = New ViewDataDictionary(Of HandleErrorInfo)(model),
. TempData = filterContext.Controller.TempData
 }
 filterContext.ExceptionHandled = True
 filterContext.HttpContext.Response.Clear()
 filterContext.HttpContext.Response.StatusCode = Me.HttpCode
 filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
 End Sub
End Class

步骤 3

将筛选器添加到GlobalFilterCollection中的( GlobalFilters.Filters ) 。 这里示例将所有 InternalServerError ( 500 ) 错误路由到错误共享视图( Views/Shared/Error.vbhtml ) 。 NotFound ( 404 ) 错误将被发送到共享视图中的ErrorHttp404.vbhtml 。 我在这里添加了 401错误,向你展示如何扩展其他HTTP错误代码。 注意,这些视图必须是共享视图,它们都使用 System.Web.Mvc.HandleErrorInfo 对象作为模型。


filters.Add(New HandleHttpErrorAttribute With {.View ="ErrorHttp401",. HttpCode = HttpStatusCode.Unauthorized})
filters.Add(New HandleHttpErrorAttribute With {.View ="ErrorHttp404",. HttpCode = HttpStatusCode.NotFound})
filters.Add(New HandleErrorAttribute With {.View ="Error"})

步骤 4

创建一个基本控制器类并在控制器中继承它。 这里步骤允许我们处理未知的操作名称,并将 HTTP 404错误提交给 HandleHttpErrorAttribute 。


Public Class BaseController
 Inherits System.Web.Mvc.Controller

 Protected Overrides Sub HandleUnknownAction(actionName As String)
 Me.ActionInvoker.InvokeAction(Me.ControllerContext,"Unknown")
 End Sub

 Public Function Unknown() As ActionResult
 Throw New HttpException(HttpStatusCode.NotFound,"The specified controller or action does not exist.")
 Return New EmptyResult
 End Function
End Class

步骤 5

创建一个在你的Global.asax 文件在 Application_Start ControllerFactory替代,然后重写它。 这里步骤允许在指定无效控制器名称时引发 HTTP 404异常。


Public Class MyControllerFactory
 Inherits DefaultControllerFactory

 Protected Overrides Function GetControllerInstance(requestContext As System.Web.Routing.RequestContext, controllerType As System.Type) As System.Web.Mvc.IController
 Try
 Return MyBase.GetControllerInstance(requestContext, controllerType)
 Catch ex As HttpException
 Return DependencyResolver.Current.GetService(Of BaseController)()
 End Try
 End Function
End Class

'In Global.asax.vb Application_Start:

controllerBuilder.Current.SetControllerFactory(New MyControllerFactory)

步骤 6

在 RoutTable.Routes 中为BaseController未知操作包含特殊路由。 这将帮助我们在用户访问未知控制器或者未知操作时引发 404.


'BaseController
routes.MapRoute( _
"Unknown","BaseController/{action}/{id}", _
 New With {.controller ="BaseController",. action ="Unknown",. id = UrlParameter.Optional} _
)

摘要

这个示例演示了如何使用MVC框架将 404 Http错误代码返回给浏览器,而无需使用过滤器属性和共享错误视图重定向。 它还演示了在指定无效控制器名称和操作名称时显示相同的自定义错误页。

我将添加一个无效的控制器名称,动作名称和自定义 404的屏幕截图,如果我获得足够的投票来发布一个=,则返回一个自定义。 当我使用这个解决方案访问以下url时,Fiddler返回 404条消息:


/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound

cottsak上的文章和这些文章的良好引用。

在 MVC4 WebAPI 404中,可以按以下方式处理:

课程 APICONTROLLER


//GET/api/courses/5
 public HttpResponseMessage<Courses> Get(int id)
 {
 HttpResponseMessage<Courses> resp = null;

 var aCourse = _courses.Where(c => c.Id == id).FirstOrDefault();

 resp = aCourse == null? new HttpResponseMessage<Courses>(System.Net.HttpStatusCode.NotFound) : new HttpResponseMessage<Courses>(aCourse);

 return resp;
 }

主控制器


public ActionResult Course(int id)
{
 return View(id);
}

视图


<div id="course"></div>
<script type="text/javascript">
 var id = @Model;
 var course = $('#course');
 $.ajax({ 
 url: '/api/courses/' + id,
 success: function (data) {
 course.text(data.Name);
 },
 statusCode: {
 404: function() 
 {
 course.text('Course not available!'); 
 }
 }
 });
</script>

全局


public static void RegisterRoutes(RouteCollection routes)
{
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 routes.MapHttpRoute(
 name:"DefaultApi",
 routeTemplate:"api/{controller}/{id}",
 defaults: new { id = RouteParameter.Optional }
 );

 routes.MapRoute(
 name:"Default",
 url:"{controller}/{action}/{id}",
 defaults: new { controller ="Home", action ="Index", id = UrlParameter.Optional }
 );
}

结果

enter image description here

在nuget上尝试 NotFoundMVC 。它工作正常,没有安装。

...