【发布时间】:2014-05-26 06:55:03
【问题描述】:
我正在使用从 RequiredAttribute 继承的自定义验证 requiredconditional 来有条件地要求某些字段。除了在一次情况下,这在任何地方都能很好地工作,我无法弄清楚发生了什么。它为模型中的一个属性调用 IsValid 方法两次(客户端验证完美运行)该模型有 2 个使用此属性的属性,但只有一个有问题。起初我认为这是因为我的一个条件是一个复选框,它同时回发了选中的值和隐藏的值,但我尝试使用单选按钮甚至隐藏值,但在所有情况下都有相同的结果。这是我的观点(为测试而简化):
@ModelType List(Of eLADNETBusiness.AdditionalInterest)
@Code
ViewData("Title") = "Bind Coverage Entry"
End Code
<h2>Bind Coverage Entry</h2>
@Using Html.BeginForm()
@Html.AntiForgeryToken()
@Html.Hidden("hullValue", ViewBag.HullValue)
Dim currentCount As Integer = 0
@For count As Integer = 0 To Model.Count - 1
currentCount = count
@<div class="editor-label">
@Html.LabelFor(Function(model) model(currentCount).LienholderAmount)
</div>
@<div class="editor-field">
@Html.EditorFor(Function(model) model(currentCount).LienholderAmount)
@Html.ValidationMessageFor(Function(model) model(currentCount).LienholderAmount)
</div>
@<div>
@Html.EditorFor(Function(model) model(currentCount).Lienholder90Percent)
</div>
Next
@<p>
<input type="submit" value="Continue" />
</p>
End Using
这是我的模型(为测试而简化):
<DataContract()> _
Public Class AdditionalInterest
<DataMember()> _
Public Property ID As Integer = 0
<RequiredConditional("Lienholder90Percent", False, ErrorMessage:="Enter Breach of Warranty lienamount or select 90 percent of insured value")> _
<Display(Name:="Lienholder Amount")> _
<DataMember()> _
Public Property LienholderAmount As Nullable(Of Integer)
<DataMember()> _
Public Property Lienholder90Percent As Boolean
结束类
还有我需要的条件属性:
Imports System.Collections.Generic
Imports System.Linq
Imports System.ComponentModel.DataAnnotations
Imports System.Web.Mvc
Imports System.Collections
Imports System.Text
Public Class RequiredConditional
Inherits RequiredAttribute
Implements IClientValidatable
Private Property PropertyNames() As String()
Private Property DesiredValues() As Object()
Public Sub New(comparePropertyNames As String(), comparePropertyDesiredValues As Object())
PropertyNames = comparePropertyNames
DesiredValues = comparePropertyDesiredValues
End Sub
Public Sub New(comparePropertyNames As String, comparePropertyDesiredValues As Object)
PropertyNames = New String() {comparePropertyNames}
DesiredValues = New String() {comparePropertyDesiredValues}
End Sub
Protected Overrides Function IsValid(value As Object, context As ValidationContext) As ValidationResult
Dim instance As Object = context.ObjectInstance
Dim type As Type = instance.GetType()
Dim propertyvalue As Object
Dim trueConditions As Integer = 0
For count As Integer = 0 To PropertyNames.Count - 1
propertyvalue = type.GetProperty(PropertyNames(count)).GetValue(instance, Nothing)
If Not propertyvalue Is Nothing Then
If DesiredValues.Count >= count + 1 Then
If propertyvalue.ToString() = DesiredValues(count).ToString() Then
trueConditions += 1
End If
End If
End If
Next
'if all conditions are met, validate value
If trueConditions = PropertyNames.Count And trueConditions = DesiredValues.Count Then
Dim result As ValidationResult = MyBase.IsValid(value, context)
Return result
End If
Return ValidationResult.Success
End Function
Public Function GetClientValidationRules(metadata As System.Web.Mvc.ModelMetadata, context As System.Web.Mvc.ControllerContext) As System.Collections.Generic.IEnumerable(Of System.Web.Mvc.ModelClientValidationRule) _
Implements System.Web.Mvc.IClientValidatable.GetClientValidationRules
Dim results As New List(Of ModelClientValidationRule)
Dim rule = New ModelClientValidationRule With {.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), .ValidationType = "requiredif"}
Dim depProp As String = String.Empty
Dim sbProp As New StringBuilder()
Dim sbTarget As New StringBuilder()
Dim helper As New ValidationHelper
For count As Integer = 0 To PropertyNames.Count - 1
Dim prop As String = PropertyNames(count)
depProp = helper.BuildDependentPropertyName(metadata, TryCast(context, ViewContext), prop)
sbProp.AppendFormat("|{0}", depProp)
Dim targetValue As String = String.Empty
If DesiredValues.Count >= count + 1 Then
targetValue = (If(DesiredValues(count), "")).ToString()
End If
If DesiredValues(count).GetType() = GetType(Boolean) Then
targetValue = DesiredValues(count).ToString.ToLower
End If
sbTarget.AppendFormat("|{0}", targetValue)
Next
rule.ValidationParameters.Add("dependentproperty", sbProp.ToString().TrimStart("|"))
rule.ValidationParameters.Add("targetvalue", sbTarget.ToString().TrimStart("|"))
results.Add(rule)
Return results
End Function
End Class
因此,当我单击提交并调试到 requiredconditional 属性时,lienholderamount 属性命中 IsValid 两次。第一次命中时, Lienholder90Percent 的值是 False,即使在模型中它是真的并且在表单上是真的(并且通过了客户端验证),所以此时验证失败。然后再次点击,Lienholder90Percent 为 True(这是正确的)并通过验证。但由于第一个失败,它仍然失败并显示错误消息。您会注意到该模型是一个列表,但出于测试目的,我只发送一个并且仍然得到相同的结果。无法弄清楚为什么它只发生在这一属性上。希望这很容易,我只是看不到。我花了一整天的时间试图弄清楚这一点。就像我说的,我经常使用这个属性并且效果很好。找不到这种情况的不同之处。
【问题讨论】:
-
所以我可以通过更改模型中属性的顺序来解决这个问题。将属性lienholder90percent 移到lienholderamount 属性上方(这取决于lienholder90percent 的值以进行验证)。会认为在调用 IsValid 函数之前设置了所有属性吗?我在之前使用此属性时很幸运,因为我所有的依赖属性都已经在属性被验证之前。
-
这也解决了我的问题 - 您应该将此作为答案提交并接受。