2010-08-31 50 views
1

我想验证我的视图中的任何2个文本框字段都提供了一个值。我做了这个型号验证:ASP.NET MVC 2问题与自定义ModelValidator

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(); %> 

回答

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()是实例的类本身,而不是财产的

+0

我喜欢它。我会尝试一下。 – 2010-08-31 17:18:14

+0

客户端验证如何? – 2010-08-31 18:12:52

+0

这肯定会需要自定义客户端验证(这里是众所周知的示例:http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx)。但不知道它将如何与类级验证一起工作。 – 2010-08-31 19:34:13

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; 
    } 
} 

因为这不是一个属性级的验证,我只好一个验证摘要添加到视图。

我仍然好奇如何将这与客户端验证挂钩。

+0

如果用户键入空格会怎么样?那么简单的空检查就不够了。 – 2010-08-31 17:52:35

+0

谢谢。固定,我想。 – 2010-08-31 18:33:44

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/,因为它与Data Annotations很好地结合在一起