我不确定您是否熟悉NerdDinner应用程序。它添加了一个方法GetRuleViolations()和一个属性IsValid到晚餐对象。保存对象时,它会检查对象是否有效。如果不是,则抛出异常。在捕获异常的控制器中,ViewData的ModelState充满了违反规则的情况,视图将重新显示。验证帮助程序突出显示错误。
我想做的是创建一个HandleRuleViolationExceptionAttribute,类似于HandleExceptionAttribute(它是MVC框架的一部分)。问题是该属性必须重新填充视图的Modelstate。
视图的模型可以有任何对象类型。抛出RuleViolationException填充的代码将RuleViolationException.Object设置为视图的模型。
我在MVC源代码中查找HandleException属性的代码,并对其进行了修改:
<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
为了填充视图的模型,我迭代了请求的表单键,并将键及其值添加到ViewData实例中。它现在起作用了,但是,我不相信这是一种方法。
在控制器的Action方法中,我可以使用UpdateModel方法更新模型。这也会更新viewStates模型状态。我可以包含一个字符串数组,其中包含必须更新的属性名,或者,当将模型作为操作参数时,我可以使用Bind属性插入或排除某些属性(就像我在上面的create操作中所做的那样)。我的方法不符合这一点,可能导致安全问题。
在OneException方法中构造ViewData对象是否有更好的方法,其工作原理与控制器的UpdateModel方法类似?是否有方法从ExceptionHandlerAttribute调用UpdateModel方法?
纪尧姆·哈尼克