问题
I have an ASP.NET MVC 2 project in which I've created a data transfer object to receive data from a web page form. The form has two groups of checkboxes on it. I want to validate the object to make sure that at least one of the checkboxes in each group is checked.
I'm doing the validation on the server side so that a user won't be able to hack around any client-side validation. (I will add client-side validation with jQuery later; that's easy.)
My understanding is that I have to create my own custom ValidationAttribute for my data transfer object class, but I don't understand how to create and use one that can accept an arbitrary list of checkbox properties to make sure that at least one of them is true. I am guessing I will have to call the attributes like this:
[AtLeastOneCheckbox("set1check1", "set1check2", "set1check3",
ErrorMessage = "You must check at least one checkbox in set 1.")]
[AtLeastOneCheckbox("set2check1", "set2check2", "set2check3", "set2check4", "set2check5",
ErrorMessage = "You must check at least one checkbox in set 2.")]
public class MyFormDTO
{
...
}
What would the implementation of AtLeastOneCheckboxAttribute look like?
Or is there a different way that I should do this kind of validation?
回答1:
if you have several checkbox groups, you just need to deine the attribute several times.
[AttributeUsage( AttributeTargets.Class)]
public class AtLeastOneCheckboxAttribute : ValidationAttribute
{
private string[] _checkboxNames;
public AtLeastOneCheckboxAttribute(params string[] checkboxNames)
{
_checkboxNames = checkboxNames;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propertyInfos = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x=>_checkboxNames.Contains(x.Name));
var values = propertyInfos.Select(x => x.GetGetMethod().Invoke(value, null));
if (values.Any(x => Convert.ToBoolean(x)))
return ValidationResult.Success;
else
{
ErrorMessage = "At least one checkbox must be selected";
return new ValidationResult(ErrorMessage);
}
}
}
UPDATE
as you have found out, class-level validation is called only after all properties pass. In order to get the error, just use empty string as the key.
回答2:
Your DTO, which is I'm guessing your ViewModel can ihert IDataErrorInfo. Then you can do your validation like this (note I didn't compile this)
//I'm guessing you have a list of checkboxes
IEnumerable<bool> checkBoxes1;
IEnumerable<bool> checkBoxes2;
public class MyFormDTO : IDataErrorInfo
{
public string this[string prop]
{
get
{
if(prop == "checkBoxes1")
{
if(checkBoxes1.Any(x => x == true))
{
return "Error: You need to select atleast one checkbox from set1";
}
}
else if(prop == "checkBoxes2")
{
if(checkBoxes2.Any(x => x == true))
{
return "Error: You need to select atleast one checkbox from set2";
}
}
return null;
}
}
public string Error { get { return null; } }
}
来源:https://stackoverflow.com/questions/4491521/an-asp-net-mvc-validator-to-make-sure-at-least-one-checkbox-is-checked