如何在MVC中的数据注释中进行条件验证

本文关键字:条件 验证 注释 MVC 数据 | 更新日期: 2023-09-27 18:27:27

我有以下型号:

public class PasswordResetModel {
public bool PasswordCreationStatus { get; set; }
[Display(Name = "AcctNumber", ResourceType = typeof(Resources.Register))]
    [ValidateMustHaveAtLeastOne("AtLeastOneShoudlbeThere", "")]
    //Account number is numeric
    [RegularExpression(@"^[0-9]+$", ErrorMessageResourceType = typeof(Resources.Register),
      ErrorMessageResourceName = "AccountNumberRegularExpr")]
    [ScriptIgnore]
    public int? AccountNumber { get; set; }
    [Display(Name = "BirthDate", ResourceType = typeof(Resources.Register))]
    [ValidateMustHaveAtLeastOne("AtLeastOneShoudlbeThere", "")]
    [ScriptIgnore]
    public string BirthDate { get; set; }
    [Display(Name = "SSN", ResourceType = typeof(Resources.Register))]
    [ValidateMustHaveAtLeastOne("AtLeastOneShoudlbeThere", "")]
    //Accepts only four digits
    [RegularExpression(@"^'d{4}$", ErrorMessageResourceType = typeof(Resources.Register),ErrorMessageResourceName = "SSNRegularExpr")]
    [StringLength(4, ErrorMessageResourceType = typeof(Resources.Register),ErrorMessageResourceName = "SSNRegularExpr")]
    [ScriptIgnore]
    public string SSN { get; set; }
}

我想确保至少输入3个(账号、SSN和出生日期)中的任何一个。ValidateMustHaveAtleteOne类如下所示。但我只想在PasswordCreationStatus为false的情况下进行验证。

ValidateMustHaveAtLeastOne类如下所示:

[AttributeUsage(AttributeTargets.Property)]
  public class ValidateMustHaveAtLeastOne : ValidationAttribute, IClientValidatable {
    #region Construnctor
    public ValidateMustHaveAtLeastOne(string groupName, string validationMessage) {
      GroupName = groupName;
      ValidationMessage = validationMessage;
    }
    #endregion
    #region Properties
    /// <summary>
    /// Name of the group of the properties
    /// </summary>
    public string GroupName { get; private set; }
    /// <summary>
    /// Vaidation message
    /// </summary>
    public string ValidationMessage { get; private set; }
    #endregion
    #region Public overrides
    /// <summary>
    /// Validates the group of properties.
    /// </summary>
    /// <param name="value">The value to validate.</param>
    /// <param name="context">The context information about the validation operation.</param>
    /// <returns>An instance of the ValidationResult class.</returns>
    protected override ValidationResult IsValid(object value, ValidationContext context) {
      foreach (var property in GetGroupProperties(context.ObjectType)) {
        var propertyValue = property.GetValue(context.ObjectInstance, null);
        if (propertyValue != null) {
          return null;
        }
      }
      return new ValidationResult(ValidationMessage);
    }
    #endregion
    #region Implementation of IClientValidateable
    /// <summary>
    /// To enable client side implementation of same validtion rule.
    /// </summary>
    /// <param name="metadata">The model metadata.</param>
    /// <param name="context">The controller context.</param>
    /// <returns>The client validation rules for this validator.</returns>
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
      var groupProperties = GetGroupProperties(metadata.ContainerType);
      List<string> propertyNames = new List<string>();
      foreach (var property in groupProperties) {
        propertyNames.Add(property.Name);
      }
      var rule = new ModelClientValidationRule {
        ErrorMessage = this.ValidationMessage
      };
      rule.ValidationType = string.Format("group", GroupName.ToLower());
      rule.ValidationParameters["propertynames"] = string.Join(",", propertyNames);
      yield return rule; // yield key word is used as return type is  declared as IEnumerable<ModelClientValidationRule>
    }
    #endregion
        /// Returns the group of properties that implements this attribute
    /// </summary>
    /// <param name="type">Type of the Model</param>
    /// <returns>List of properties</returns>
    private IEnumerable<PropertyInfo> GetGroupProperties(Type type) {
      var propertyInfo = new List<PropertyInfo>();
      foreach (PropertyInfo property in type.GetProperties()) {
        if (property.GetCustomAttributes(typeof(ValidateMustHaveAtLeastOne), false).GetLength(0) > 0) {
          propertyInfo.Add(property);
        }
      }
      return propertyInfo;
    }

  }

我认为这是可能的最低限度的增强。如有任何帮助,我们将不胜感激。提前谢谢。

如何在MVC中的数据注释中进行条件验证

更新Validation以验证依赖属性是否与目标值匹配,然后进行验证。

[AttributeUsage(AttributeTargets.Property)]
public class ValidateMustHaveAtLeastOne : ValidationAttribute, IClientValidatable {
#region Construnctor
public ValidateMustHaveAtLeastOne(string groupName, string validationMessage, string dependentProperty, object targetValue) {
  GroupName = groupName;
  ValidationMessage = validationMessage;
  DependentProperty = dependentProperty;
  TargetValue = targetValue;
}
#endregion
#region Properties
/// <summary>
/// Name of the group of the properties
/// </summary>
public string GroupName { get; private set; }
/// <summary>
/// Vaidation message
/// </summary>
public string ValidationMessage { get; private set; }
/// <summary>
/// Gets or sets the dependent property.
/// </summary>
/// <value>
/// The dependent property.
/// </value>
public string DependentProperty { get; set; }
/// <summary>
/// Gets or sets the target value.
/// </summary>
/// <value>
/// The target value.
/// </value>
public object TargetValue { get; set; }
#endregion
#region Public overrides
/// <summary>
/// Validates the group of properties.
/// </summary>
/// <param name="value">The value to validate.</param>
/// <param name="context">The context information about the validation operation.</param>
/// <returns>An instance of the ValidationResult class.</returns>
protected override ValidationResult IsValid(object value, ValidationContext context) {
    var containerType = validationContext.ObjectInstance.GetType();
    var field = containerType.GetProperty(this.DependentProperty);
    if (field != null)
    {
        // get the value of the dependent property
        var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);
        // compare the value against the target value
        if ((dependentvalue == null && this.TargetValue == null)
            || (dependentvalue != null && dependentvalue.Equals(this.TargetValue)))
        {
            foreach (var property in GetGroupProperties(context.ObjectType)) {
            var propertyValue = property.GetValue(context.ObjectInstance, null);
            if (propertyValue != null) {
              return null;
                }
          }
          return new ValidationResult(ValidationMessage);
        }
    }
  return ValidationResult.Success;
}
#endregion
#region Implementation of IClientValidateable
/// <summary>
/// To enable client side implementation of same validtion rule.
/// </summary>
/// <param name="metadata">The model metadata.</param>
/// <param name="context">The controller context.</param>
/// <returns>The client validation rules for this validator.</returns>
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
  var groupProperties = GetGroupProperties(metadata.ContainerType);
  List<string> propertyNames = new List<string>();
  foreach (var property in groupProperties) {
    propertyNames.Add(property.Name);
  }
  var rule = new ModelClientValidationRule {
    ErrorMessage = this.ValidationMessage
  };
  rule.ValidationType = string.Format("group", GroupName.ToLower());
  rule.ValidationParameters["propertynames"] = string.Join(",", propertyNames);
  string depProp = this.BuildDependentPropertyId(metadata, context as ViewContext);
  // find the value on the control we depend on; if it's a bool, format it javascript style
  string targetValue = (this.TargetValue ?? string.Empty).ToString();
  if (this.TargetValue.GetType() == typeof(bool))
  {
     targetValue = targetValue.ToLower();
  }
  rule.ValidationParameters["dependentproperty"] = depProp;
  rule.ValidationParameters["targetvalue"] = targetValue;
  yield return rule; // yield key word is used as return type is  declared as IEnumerable<ModelClientValidationRule>
}
#endregion
    /// Returns the group of properties that implements this attribute
/// </summary>
/// <param name="type">Type of the Model</param>
/// <returns>List of properties</returns>
private IEnumerable<PropertyInfo> GetGroupProperties(Type type) {
  var propertyInfo = new List<PropertyInfo>();
  foreach (PropertyInfo property in type.GetProperties()) {
    if (property.GetCustomAttributes(typeof(ValidateMustHaveAtLeastOne), false).GetLength(0) > 0) {
      propertyInfo.Add(property);
    }
  }
  return propertyInfo;
}
 private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
{
    string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty);
    // This will have the name of the current field appended to the beginning, because the TemplateInfo's context has had this fieldname appended to it.
    var thisField = metadata.PropertyName + "_";
    if (depProp.StartsWith(thisField, StringComparison.OrdinalIgnoreCase))
    {
        depProp = depProp.Substring(thisField.Length);
    }
    return depProp;
} 
}

用法

 [ValidateMustHaveAtLeastOne("AtLeastOneShoudlbeThere", "", "PasswordCreationStatus", false)]

您可以使用已完成(测试)的库在某些条件下进行验证。

有很多这样的库,但最著名的可能是万无一失的

在上面的链接中,您可以看到它的用法和文档。

我认为以下验证属性适合您的情况。

[RequiredIfTrue("PasswordCreationStatus")]

您可以添加一个计算的属性,该属性只有在至少提供一个属性时才有效:

public class PasswordResetModel 
{
    public bool PasswordCreationStatus { get; set; }
    [Display(Name = "AcctNumber", ResourceType = typeof(Resources.Register))]        
    //Account number is numeric
    [RegularExpression(@"^[0-9]+$", ErrorMessageResourceType = typeof(Resources.Register),
      ErrorMessageResourceName = "AccountNumberRegularExpr")]
    [ScriptIgnore]
    public int? AccountNumber { get; set; }
    [Display(Name = "BirthDate", ResourceType = typeof(Resources.Register))]        
    [ScriptIgnore]
    public string BirthDate { get; set; }
    [Display(Name = "SSN", ResourceType = typeof(Resources.Register))]      
    //Accepts only four digits
    [RegularExpression(@"^'d{4}$", ErrorMessageResourceType = typeof(Resources.Register),ErrorMessageResourceName = "SSNRegularExpr")]
    [StringLength(4, ErrorMessageResourceType = typeof(Resources.Register),ErrorMessageResourceName = "SSNRegularExpr")]
    [ScriptIgnore]
    public string SSN { get; set; }
    [Required(ErrorMessage = "Must Have At Least One of the properties")]
    public string MustHaveAtLeastOneIsValid {
       get{
           return  this.SSN != null || this.BirthDate != null || this.AccountNumber.HasValue ? "valid": null;
       }
    }
}