我不确定您是否熟悉NerdDinner应用程序。它向Dinner对象添加一个方法GetRuleViolations()和一个属性IsValid。当对象被保存时,它检查对象是否有效。如果不是,则会引发异常。在捕获异常的控制器中,ViewData的ModelState被违反规则填充,并重新显示视图。 Html.Validation助手突出显示错误。ASP.NET MVC:如何为异常过滤器创建ViewData
我想要做的是创建一个HandleRuleViolationExceptionAttribute,类似于HandleExceptionAttribute(它是MVC框架的一部分)。问题是这个属性必须重新填充视图的模型状态。
视图可以有任何对象类型为其模型。引发RuleViolationException填充的代码将RuleViolationException.Object设置为View的模型。
我抬头代码为HandleExceptionAttribute MVC中的源代码,并修改了它:
<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method, _
Inherited:=True, AllowMultiple:=False)> _
Public Class HandleRuleViolationExceptionAttribute
Inherits FilterAttribute
Implements IExceptionFilter
Private m_View As String
Private m_MasterPage As String
Public Property View() As String
Get
Return m_View
End Get
Set(ByVal value As String)
m_View = value
End Set
End Property
Public Property MasterPage() As String
Get
Return If(m_MasterPage, String.Empty)
End Get
Set(ByVal value As String)
m_MasterPage = value
End Set
End Property
Public Sub OnException(ByVal filterContext As System.Web.Mvc.ExceptionContext) _
Implements System.Web.Mvc.IExceptionFilter.OnException
If filterContext Is Nothing Then
Throw New ArgumentException("filterContext is null")
End If
'Ignore if the error is already handled.
If filterContext.ExceptionHandled Then Return
'Handle only ObjectIsInvalidExceptions.
If Not TypeOf filterContext.Exception Is ObjectIsInvalidException Then
Return
End If
Dim ex As ObjectIsInvalidException = DirectCast(filterContext.Exception, ObjectIsInvalidException)
'If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
'ignore it.
If (New HttpException(Nothing, ex).GetHttpCode()) <> 500 Then Return
Dim actionName As String = CStr(filterContext.RouteData.Values("action"))
Dim viewName As String = If(String.IsNullOrEmpty(View), actionName, View)
Dim viewData = filterContext.Controller.ViewData
viewData.Model = ex.Object
For Each item As String In filterContext.HttpContext.Request.Form.Keys
viewData.Add(item, filterContext.HttpContext.Request.Form.Item(item))
Next
For Each ruleViolation In ex.Object.GetRuleViolations()
viewData.ModelState.AddModelError(ruleViolation.PropertyName, ruleViolation.ErrorMessage)
Next
filterContext.Result = New ViewResult() With _
{ _
.ViewName = viewName, _
.MasterName = MasterPage, _
.ViewData = viewData, _
.TempData = filterContext.Controller.TempData _
}
filterContext.ExceptionHandled = True
filterContext.HttpContext.Response.Clear()
filterContext.HttpContext.Response.StatusCode = 500
'Certain versions of IIS will sometimes use their own error page when
'they detect a server error. Setting this property indicates that we
'want it to try to render ASP.NET MVC's error page instead.
filterContext.HttpContext.Response.TrySkipIisCustomErrors = True
End Sub
End Class
来填充视图的Model我遍历请求的形式键和添加键值并将其值的ViewData的实例。它现在可以工作,但是,我不认为这是做到这一点的方法。
在Controller的Action方法中,我可以使用UpdateModel方法更新模型。这也更新了viewStates ModelState。我可以包含具有必须更新的属性名称的字符串数组,或者将模型作为Action参数时,我可以使用Bind属性来排除或者排除某些属性(就像我在create-action中所做的那样)以上)。我的方法不遵守这一点,可能导致安全问题。
有没有更好的方法在OnException方法中构造ViewData对象,它的作用类似于控制器的UpdateModel方法?有没有办法从ExceptionHandlerAttribute调用UpdateModel方法?
感谢, 纪尧姆Hanique
谢谢您的回复! 该属性确实有一个可以设置的View属性,但如果不是,Action名称将用作View名称。 我确实有和你一样的想法:filterContext.Controller.UpdateModel但是filterContext.Controller的类型是ControllerBase,它没有UpdateModel方法。任何其他想法? 我可以将真实的控制器实例传递给此属性(控制器的Action中的this/Me)并使用它来更新模型? – 2009-08-21 08:47:06
好点。我错过了。通过代码回顾,我实际上认为在这里完成这项工作所需的最少工作量非常大。通过将viewData.Model设置为ex.Object,您可以达到同样的效果。我会认为你会从ex.Object获取所有表单数据?也许不会。 – 2009-08-21 14:30:09
我放弃了。如果UpdateModel是调用的方法,我甚至不确定。即使是这样,我也搞不明白。有没有人知道如何在设置视图的Model属性时更新ModelState? – 2009-08-23 09:33:27