【发布时间】:2009-08-23 19:26:50
【问题描述】:
我不确定您是否熟悉 NerdDinner 应用程序。它将方法 GetRuleViolations() 和属性 IsValid 添加到 Dinner 对象。保存对象时,它会检查对象是否有效。如果不是,它会引发异常。在捕获到异常的控制器中,ViewData 的 ModelState 被规则违规填充并重新显示视图。 Html.Validation 帮助器突出显示错误。
我想做的是创建一个 HandleRuleViolationExceptionAttribute,类似于 HandleExceptionAttribute(它是 MVC 框架的一部分)。问题是这个属性必须重新填充视图的模型状态。
视图的模型可以有任何对象类型。引发 RuleViolationException 填充的代码将 RuleViolationException.Object 设置为 View 的 Model。
我在MVC源码中查找了HandleExceptionAttribute的代码并修改了:
<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 ModelState。我可以包含一个字符串数组,其中包含必须更新的属性名称,或者,当将模型作为 Action 参数时,我可以使用 Bind-attribute 来添加或排除某些属性(就像我在 create-action 中所做的那样以上)。我的方法不遵守这个,可能会导致安全问题。
有没有更好的方法在 OnException 方法中构造 ViewData 对象,其工作方式类似于控制器的 UpdateModel 方法?有没有办法从 ExceptionHandlerAttribute 调用 UpdateModel 方法?
谢谢, 纪尧姆·哈尼克
【问题讨论】:
标签: asp.net-mvc