Home > other >  How can I check if Model.IsValid when I want to have at least one checkbox value be true?
How can I check if Model.IsValid when I want to have at least one checkbox value be true?

Time:09-17

I have a model with many checkboxes. This model can only be valid if at least one of the boxes has been checked and the date has been selected. The model looks like this:

public class CustomDistricts4Weeks
{
    [DisplayName("002")]
    public bool D2 { get; set; }
    [DisplayName("003")]
    public bool D3 { get; set; }
    [DisplayName("004")]
    public bool D4 { get; set; }
    [DisplayName("005")]
    public bool D5 { get; set; }
    [DisplayName("006")]
    public bool D6 { get; set; }
    [DisplayName("007")]
    public bool D7 { get; set; }
    [DisplayName("ARL")]
    public bool DArl { get; set; }
    [DisplayName("BAR")]
    public bool DBar { get; set; }
    [DisplayName("COL")]
    public bool DCol { get; set; }
    [DisplayName("GER")]
    public bool DGer { get; set; }
    [DisplayName("MEM")]
    public bool DMem { get; set; }
    [DisplayName("LAK")]
    public bool DLak { get; set; }
    [DisplayName("MIL")]
    public bool DMil { get; set; }
    [DisplayName("JAIL")]
    public bool DJail { get; set; }
    [DisplayName("JAILEAST")]
    public bool DJailEast { get; set; }
    [DisplayName("SCCC")]
    public bool DSCCC { get; set; }
    [DisplayName("1USD")]
    public bool D1USD { get; set; }
    [DisplayName("2USD")]
    public bool D2USD { get; set; }
            
    [DataType(DataType.Date, ErrorMessage = "Date Only")]
    [DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}", ApplyFormatInEditMode = true)]
    [Display(Name = "To Date")]
    public DateTime ToDate { get; set; }
}

I'm sure I can just put [Required] on the ToDate but how can I make sure that at least one of the bools is true? Any number can be true but at least one must be true. I may not be approaching this issue correctly and I would be eager to learn a better approach. My code is working but I am trying to build a validation.

CodePudding user response:

Define a custom validation attribute and apply it to the class.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ModelValidationAttribute : ValidationAttribute
{        
    public ModelValidationAttribute(string errorMessage)
        : base(errorMessage)
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (validationContext.ObjectInstance is CustomDistricts4Weeks model)
        {
            if (model.D2 || model.D3 || model.D4 ...)
            {
                return ValidationResult.Success;
            }
        }
        return new ValidationResult(ErrorMessage);
    }
}

Applying the ModelValidationAttribute attribute to the data model class:

[ModelValidation("Select at least one checkbox")]
public class CustomDistricts4Weeks
{
    [DisplayName("002")]
    public bool D2 { get; set; }

    ...

}

The IsValid() method of the custom attribute might be changed to use reflection to enumerate all properties in the model. In this case, do not need to use all properties name. Of course only in case all bool properties should be tested:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    var model = (Movie)validationContext.ObjectInstance;
    PropertyInfo[] myPropertyInfo  = model.GetType().GetProperties();
    for (int i = 0; i < myPropertyInfo.Length; i  )
    {
        var prop = myPropertyInfo[i];               
        if (prop.PropertyType.Equals(typeof(bool)) 
            && prop.GetCustomAttributes(typeof(DisplayNameAttribute), false).Length > 0
            && prop.GetValue(model) is bool pval && pval)
        {
            return ValidationResult.Success;                    
        }
    }
    return new ValidationResult(ErrorMessage);
}
  • Related