.net MVC3有条件地验证依赖于父对象属性的属性

.net MVC3有条件地验证依赖于父对象属性的属性,.net,asp.net-mvc-3,validation,.net,Asp.net Mvc 3,Validation,我有以下ViewModel: public class StayDetails { public int NumberOfRooms { get; set; } public IList<RoomDetail> Rooms { get;set; } } public class RoomDetail { public int RoomNumber { get; set; } [MinIfRoomRequired("StayDetails.Numbe

我有以下ViewModel:

public class StayDetails
{
    public int NumberOfRooms { get; set; }
    public IList<RoomDetail> Rooms { get;set; }
}

public class RoomDetail
{
    public int RoomNumber { get; set; }

    [MinIfRoomRequired("StayDetails.NumberOfRooms", "RoomNumber", 1]
    public int NumberOfAdults { get;set; }
}
我遇到的问题是无法访问NumberOfRooms属性,validationContext.ObjectInstance没有任何对父对象的引用。我考虑在对象初始化期间将对StayDetails对象的引用添加到RoomDetails对象上,这样我就可以从那里引用属性,但是模型绑定不允许这样做,因为RoomDetail对象没有无参数构造函数

有什么建议吗

非常感谢,

David

您可以尝试使用FluentValidation进行验证。

写得少做得多…

您应该在
StateDetails类
上定义验证注释,而不是RoomDetail。通过这种方式,您将获得所有值、NumberOfRooms、房间列表及其各自的RoomNumber和NumberOfOfOf。相应地更改您的验证器。

我能够通过使用自定义绑定解决此问题。您需要添加一个属性以引用回父对象,例如NumberOfRooms。在我的例子中,我实际上创建了一个委托,它引用回父对象中的例程。为我在stackoverflow中遇到的VB代码和格式问题提前道歉

  • 在子对象上创建NumberOfRooms属性
  • 为子对象类创建自定义模型绑定器。此模型活页夹将执行以下几项操作: a) 为NumberOfRooms插入一个值(在我的例子中,我设置了一个委托) b) 将元数据/密钥信息存储在控制器字典中,以便稍后用于重新验证
  • 例如:

    Public Class RoomDetail_Binder
        Inherits DefaultModelBinder
    
        Protected Overrides Function CreateModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext, modelType As Type) As Object
            Dim theObj As Quote_Equipment_Model = MyBase.CreateModel(controllerContext, bindingContext, modelType)
            Dim theParent As StayDetails= controllerContext.HttpContext.Items("StayDetails")
            If Not IsNothing(theParent) Then
                theObj.NumberOfRooms=theParent.NumberOfRooms
            End If
            Return theObj
        End Function
    
        Protected Overrides Sub OnModelUpdated(controllerContext As ControllerContext, bindingContext As ModelBindingContext)
            MyBase.OnModelUpdated(controllerContext, bindingContext)
            Dim theMetadataList As List(Of MetaDataPair)
            If Not controllerContext.HttpContext.Items.Contains("MetadataList") Then
                theMetadataList = New List(Of MetaDataPair)
                controllerContext.HttpContext.Items.Add("MetadataList", theMetadataList)
            Else
                theMetadataList = controllerContext.HttpContext.Items("MetadataList")
            End If
            theMetadataList.Add(New MetaDataPair With {.Metadata = bindingContext.ModelMetadata, .BindingModelName = bindingContext.ModelName})
        End Sub
    
    End Class
    
    请注意,MetadataList只是

    Public Class MetaDataPair
        Public Property BindingModelName As String
        Public Property Metadata As ModelMetadata
    End Class
    
  • 接下来,我为父对象创建一个自定义绑定器:这还做了几件事:

    a) 将父对象存储在controllercontext中,以便子对象可以使用它。 b) 重新验证子对象

    公共类Staydeails\u活页夹 继承DefaultModelBinder

    Protected Overrides Function CreateModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext, modelType As Type) As Object
        Dim theObj As StayDetails = MyBase.CreateModel(controllerContext, bindingContext, modelType)
        controllerContext.HttpContext.Items("StayDetails") = theObj
        Return theObj
    End Function
    
    Public Overrides Function BindModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As Object
        Dim theObj As StayDetails = MyBase.BindModel(controllerContext, bindingContext)
        Dim theMetadataList As List(Of MetaDataPair) = CType(controllerContext.HttpContext.Items("MetadataList"), List(Of MetaDataPair))
        For Each Metadata In theMetadataList
            For Each result As ModelValidationResult In ModelValidator.GetModelValidator(Metadata.Metadata, controllerContext).Validate(Nothing)
                Dim key As String = CreateSubPropertyName(Metadata.BindingModelName, result.MemberName)
                If Not bindingContext.ModelState(key).Errors.Any(Function(ent) ent.ErrorMessage = result.Message) Then
                    bindingContext.ModelState.AddModelError(key, result.Message)
                End If
            Next
        Next
        Return theObj
    End Function
    
    末级

  • 适当地装饰你的子类

    公共教室详细信息

  • 设置控制器,使其使用自定义活页夹:

    (此处为您的参数名称)

  • 如果在未填充NumberOfRooms属性的情况下验证验证程序,请确保将其设置为成功。绑定将为您的子类执行两次验证器。第一次填充属性之前,然后在填充属性之后再次填充


  • 为了确认,我将从RoomDetail对象的NumberOfMandactors字段中删除验证,并在可以执行所需逻辑时向Rooms属性添加自定义验证程序,是否会对RoomDetail属性执行任何验证?因为我们没有将“IList Rooms”标记为[必需],如果房间属性为空,则不会验证它。但它将对Rooms集合中列出的所有RoomDetail对象执行验证。是的,它将验证所有可用对象的RoomDetail属性。嗨,Priyank,那太好了,我现在有了更好的理解。
    Protected Overrides Function CreateModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext, modelType As Type) As Object
        Dim theObj As StayDetails = MyBase.CreateModel(controllerContext, bindingContext, modelType)
        controllerContext.HttpContext.Items("StayDetails") = theObj
        Return theObj
    End Function
    
    Public Overrides Function BindModel(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As Object
        Dim theObj As StayDetails = MyBase.BindModel(controllerContext, bindingContext)
        Dim theMetadataList As List(Of MetaDataPair) = CType(controllerContext.HttpContext.Items("MetadataList"), List(Of MetaDataPair))
        For Each Metadata In theMetadataList
            For Each result As ModelValidationResult In ModelValidator.GetModelValidator(Metadata.Metadata, controllerContext).Validate(Nothing)
                Dim key As String = CreateSubPropertyName(Metadata.BindingModelName, result.MemberName)
                If Not bindingContext.ModelState(key).Errors.Any(Function(ent) ent.ErrorMessage = result.Message) Then
                    bindingContext.ModelState.AddModelError(key, result.Message)
                End If
            Next
        Next
        Return theObj
    End Function