这是使用 MVC 工具的另一种方法,您可以处理对错误控制器名称、错误路由名称以及您认为适合 Action 方法内部的任何其他条件的请求。就个人而言,我更喜欢尽可能避免使用 web.config 设置,因为它们会执行 302 / 200 重定向并且不支持Server.Transfer
使用 Razor 视图的 ResponseRewrite ( )。出于搜索引擎优化的原因,我更愿意返回带有自定义错误页面的 404。
其中一些是对上述cottsak技术的新看法。
此解决方案还使用有利于 MVC 3 错误过滤器的最小 web.config 设置。
用法
只需从操作或自定义 ActionFilterAttribute 中抛出 HttpException。
Throw New HttpException(HttpStatusCode.NotFound, "[Custom Exception Message Here]")
第1步
将以下设置添加到您的 web.config。这是使用 MVC 的 HandleErrorAttribute 所必需的。
<customErrors mode="On" redirectMode="ResponseRedirect" />
第2步
添加类似于 MVC 框架的 HandleErrorAttribute 的自定义 HandleHttpErrorAttribute,除了 HTTP 错误:
<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 步
将过滤器添加GlobalFilters.Filters
到Global.asax
. 此示例将所有 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 步
创建一个 ControllerFactory 覆盖,并在 Application_Start 的 Global.asax 文件中覆盖它。此步骤允许我们在指定无效控制器名称时引发 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 Unknown 操作包含一个特殊路由。这将帮助我们在用户访问未知控制器或未知操作的情况下引发 404。
'BaseController
routes.MapRoute( _
"Unknown", "BaseController/{action}/{id}", _
New With {.controller = "BaseController", .action = "Unknown", .id = UrlParameter.Optional} _
)
概括
此示例演示了如何使用 MVC 框架向浏览器返回 404 Http 错误代码,而无需使用过滤器属性和共享错误视图进行重定向。它还演示了在指定无效控制器名称和操作名称时显示相同的自定义错误页面。
如果我获得足够的票数来发布一个 =),我将添加无效控制器名称、操作名称和从 Home/TriggerNotFound 操作引发的自定义 404 的屏幕截图 =)。当我使用此解决方案访问以下 URL 时,Fiddler 返回 404 消息:
/InvalidController
/Home/InvalidRoute
/InvalidController/InvalidRoute
/Home/TriggerNotFound
上面cottsak 的帖子和这些文章都是很好的参考。