Я не уверен, знакомы ли вы с приложением NerdDinner. Он добавляет метод GetRuleViolations () и свойство IsValid к объекту Dinner. Когда объект сохраняется, он проверяет, является ли объект действительным. Если это не так, это вызывает исключение. В контроллере, в котором обнаружено это исключение, ModelState объекта ViewData заполняется нарушениями правил, и представление отображается повторно. Помощники Html.Validation выделяют ошибки.
Что я хотел бы сделать, это создать атрибут HandleRuleViolationExceptionAttribute, аналогичный атрибуту HandleExceptionAttribute (который является частью MVC Framework). Проблема заключается в том, что этот атрибут должен заполнять состояние модели представления.
Вид может иметь любой тип объекта для своей модели. Код, который генерирует исключения RuleViolationException, устанавливает RuleViolationException.Object для модели представления.
Я посмотрел код для 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
Чтобы заполнить модель представления, я перебираю ключи формы запроса и добавляю ключ и его значение в экземпляр ViewData. Теперь это работает, однако я не верю, что это способ сделать это.
В методе Controller's Action я мог бы обновить модель с помощью метода UpdateModel. Это также обновляет viewStates ModelState. Я могу включить массив строк с именами свойств, которые должны быть обновлены, или, имея модель в качестве параметра Action, я мог бы использовать атрибут Bind для включения или исключения некоторых свойств (как я делаю в create-action). выше). Мой метод не придерживается этого, что может привести к проблемам с безопасностью.
Есть ли лучший способ создания объекта ViewData в методе OnException, который работает аналогично методу UpdateModel контроллера? Есть ли способ вызвать метод UpdateModel из ExceptionHandlerAttribute?
Спасибо,
Гийом Ханик