我正在尝试验证视图中的两个文本框字段中的任何一个都提供了值。我做了这个模型验证器:
public class RequireEitherValidator : ModelValidator
{
private readonly string compareProperty;
private readonly string errorMessage;
public RequireEitherValidator(ModelMetadata metadata,
ControllerContext context, string compareProperty, string errorMessage)
: base(metadata, context)
{
this.compareProperty = compareProperty;
this.errorMessage = errorMessage;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (Metadata.Model == null)
yield break;
var propertyInfo = container.GetType().GetProperty(compareProperty);
if (propertyInfo == null)
throw new InvalidOperationException("Unknown property:" + compareProperty);
string valueToCompare = propertyInfo.GetValue(container, null).ToString();
if (string.IsNullOrEmpty(Metadata.Model.ToString()) && string.IsNullOrEmpty(valueToCompare))
yield return new ModelValidationResult
{
Message = errorMessage
};
}
}
这个验证逻辑永远不会被击中,我认为这是因为没有值提供给文本框。
如果您需要它,这里是我创建的提供者和属性以及属性用法:
public class MyValidatorProvider : AssociatedValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(
ModelMetadata metadata, ControllerContext context,
IEnumerable<Attribute> attributes)
{
foreach (var attrib in attributes.OfType<RequireEitherAttribute>())
yield return new RequireEitherValidator(metadata, context,
attrib.CompareProperty, attrib.ErrorMessage);
}
}
public class RequireEitherAttribute : Attribute
{
public readonly string CompareProperty;
public string ErrorMessage { get; set; }
public RequireEitherAttribute(string compareProperty)
{
CompareProperty = compareProperty;
}
}
public class StudentLogin
{
[DisplayName("Last Name")]
[Required(ErrorMessage = "You must supply your last name.")]
public string LastName { get; set; }
[DisplayName("Student ID")]
[RegularExpression(@"^\d{1,8}$", ErrorMessage = "Invalid Student ID")]
[RequireEither("SSN", ErrorMessage = "You must supply your student id or social security number.")]
public int? StudentId { get; set; }
[DisplayName("Social Security Number")]
[RegularExpression(@"^\d{9}|\d{3}-\d{2}-\d{4}$", ErrorMessage = "Invalid Social Security Number")]
public string SSN { get; set; }
}
我的观点:
<%Html.BeginForm(); %>
<p>
Please supply the following information to login:</p>
<ol class="standard">
<li>
<p>
<%=Html.LabelFor(x => x.LastName) %><br />
<%=Html.TextBoxFor(x => x.LastName)%>
<%=Html.ValidationMessageFor(x => x.LastName) %></p>
</li>
<li>
<p>
<%=Html.LabelFor(x => x.StudentId) %><br />
<%=Html.TextBoxFor(x => x.StudentId) %>
<%=Html.ValidationMessageFor(x => x.StudentId) %></p>
<p style="margin-left: 4em;">
- OR -</p>
<p>
<%=Html.LabelFor(x => x.SSN)%><br />
<%=Html.TextBoxFor(x => x.SSN) %>
<%=Html.ValidationMessageFor(x => x.SSN) %>
</p>
</li>
</ol>
<%=Html.SubmitButton("submit", "Login") %>
<%Html.EndForm(); %>
答案 0 :(得分:1)
解决这个问题的一种方法不仅仅是创建ValidationAttribute并在类级别应用它。
[RequireEither("StudentId", "SSN")]
public class StudentLogin
错误消息将自动显示在验证摘要中。该属性看起来像这样(我为了简洁起见,通过将所有内容视为字符串,大大简化了IsValid()中的验证逻辑:
public class RequireEither : ValidationAttribute
{
private string firstProperty;
private string secondProperty;
public RequireEither(string firstProperty, string secondProperty)
{
this.firstProperty = firstProperty;
this.secondProperty = secondProperty;
}
public override bool IsValid(object value)
{
var firstValue = value.GetType().GetProperty(this.firstProperty).GetValue(value, null) as string;
var secondValue = value.GetType().GetProperty(this.secondProperty).GetValue(value, null) as string;
if (!string.IsNullOrWhiteSpace(firstValue))
{
return true;
}
if (!string.IsNullOrWhiteSpace(secondValue))
{
return true;
}
// neither was supplied so it's not valid
return false;
}
}
请注意,在这种情况下,传递给IsValid()的对象是类本身的实例而不是属性。
答案 1 :(得分:1)
我喜欢Steve和Ronnie解决方案,虽然他们创建的自定义属性可能用于其他类/属性对,但我不喜欢“魔术字符串”和反映这样一个简单的情况,我通常会创建一个验证这恰好适合手头的情景。
例如,在这种情况下,我会创建类似的东西:
[AttributeUsage(AttributeTargets.Class)]
public class RequireStudentInfoAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var student = value as StudentLogin;
if(student == null)
{
return false;
}
if (student.StudentId.HasValue || !string.IsNullOrEmpty(student.SSN))
{
return true;
}
return false;
}
}
只需将它应用于StudentLogin类,如:
[RequireStudentInfo]
public class StudentLogin
关于客户端验证,我通常会选择http://xval.codeplex.com/,因为它与数据注释很好地集成
答案 2 :(得分:0)
使用史蒂夫的建议只做了一些小改动:
public class RequireEitherAttribute : ValidationAttribute
{
private string firstProperty;
private string secondProperty;
public RequireEitherAttribute(string firstProperty, string secondProperty)
{
this.firstProperty = firstProperty;
this.secondProperty = secondProperty;
}
public override bool IsValid(object value)
{
object firstValue = value.GetType().GetProperty(firstProperty).GetValue(value, null);
object secondValue = value.GetType().GetProperty(secondProperty).GetValue(value, null);
return InputSupplied(firstValue) || InputSupplied(secondValue);
}
private bool InputSupplied(object obj)
{
if (obj == null)
return false;
if (obj is string)
{
string str = (string)obj;
if (str.Trim() == string.Empty)
return false;
}
return true;
}
}
由于这不是属性级别验证,我不得不在视图中添加验证摘要。
我仍然对如何将其与客户端验证联系起来感到好奇。