问题
I'm doing validation on a lengthy form using a custom attribute. One of the incoming fields is a long series of checkboxes that I'm using to allow users to set multiple values for the corresponsing database field (I know that I could use a MultiSelectList, but I'm not a big fan of them). I'm then assembling the various checkbox values in the POST method of the ActionResult into a single string before loading it into the database. That part works well.
But, I need to validate that they've checked at least one checkbox (i.e. the database value itself can't be null). So I wrote a custom validation attribute that looks for the presence of each checkbox, and if at least one is present, then it passes the validation. Here's the code I wrote for the validation itself:
public class ConfirmLAAttribute : ValidationAttribute
{
public ConfirmLAAttribute()
{
}
protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
{
string lAppTest = String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAAccent") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAShade") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAArticulation") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAMassing") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAScreening") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LARock") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAEdging") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAWindbreak") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAGroundcover") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LANaturalizing") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAOrchard") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LATopiary") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAHerb") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LAContainer") != null) ? "X" : String.Empty;
lAppTest += (validationContext.ObjectType.GetProperty("LABog") != null) ? "X" : String.Empty;
if (String.IsNullOrEmpty(lAppTest)) {
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return ValidationResult.Success;
}
}
I'm calling the validation as an attribute on the View Model:
[ConfirmLA(ErrorMessage = "You must select at least one Landscape Application!")]
public string Landscape_Application { get; set; }
The HTML code in the view model is simply a repeat of:
<input type="checkbox" name="LAAccent" value="true" /> Accent/Feature<br />
inside of a table (i.e. this 15 times, one for each checkbox).
The problem is that this is always throwing the error. I've debugged inside the validation code itself, and it is not recognizing any of the checkboxes by their property names. In other words, each one of these:
lAppTest += (validationContext.ObjectType.GetProperty("LAAccent") != null) ? "X" : String.Empty;
is resolving to null, even if the checkbox was checked. I've further confirmed that the checked values are definitely present in the FormCollection in the ActionResult. It's as though I've got the syntax wrong or something, like the GetProperty method is not finding these checkboxes by their property names. What am I doing wrong here?
回答1:
Change your View model to be
[Required(ErrorMessage = "You must select at least one Landscape Application!")]
public ICollection<string> LandscapeServices { get; set; }
Change your Html to be
<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAAccent" /> Accent/Feature<br />
<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAShade" /> Accent/Feature<br />
<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAArticulation" /> Accent/Feature<br />
/*etc etc*/
When you hit submit all chosen values will be added to the property LandscapeServices.
Note that this will only work for server side validation. If you want client side validation you would have to create an extension on Required with your own javascript validation function.
EDIT - to address @ScubaSteve's comment about client side validation from SO answer
$(function(){
$.validator.addMethod('required_group', function(value, element) {
var $module = $(element).parents('form');
return $module.find('input.checkbox:checked').length;
}, 'Select at least one Service please');
$.validator.addClassRules('required-checkbox', { 'required_group' : true });
回答2:
I wouldn't use an attribute for this, unless you wanted to do client-side validation. Instead, I'd just make your model derive from IValidatableObject and do the validation in the IsValid method of that. Much easier, and no late binding.
来源:https://stackoverflow.com/questions/9491772/mvc-3-custom-validation-attribute-for-multiple-checkboxes