这是使用MVC工具的另一种方法,可以处理对错误的控制器名称,错误的路由名称以及您认为适合于Action方法的任何其他条件的请求。就我个人而言,我宁愿避免尽可能多的web.config设置,因为它们执行302/200重定向,并且不支持Server.Transfer
使用Razor视图的ResponseRewrite()。由于SEO的原因,我希望返回带有自定义错误页面的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步
添加类似于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
第三步
在中将过滤器添加到GlobalFilterCollection(GlobalFilters.Filters
)Global.asax
。本示例将所有InternalServerError(500)错误路由到Error共享视图(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"})
第四步
创建一个基本控制器类,并在您的控制器中继承它。此步骤使我们能够处理未知的操作名称,并将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帖子和这些文章是很好的参考。