How do I set multiple error messages for different scenarios in a Custom validation attribute?
I'm just getting to grips with custom validation attributes, and I'm trying to write a custom validation attirbute which will be placed at class level to validate against multiple properties of my model.
I can access all properties on my model, and I want to be able to check for multiple conditions in my IsValid overload, and report on them, having different error messages as follows (simplistic example).
public override bool IsValid(object value)
{
var model = (MyObject) value;
//if this value is set, I don't want to do anything other checks
if (model.Prop3)
{
return true;
}
if (model.Prop1 == "blah" && model.Prop2 == 1)
{
ErrorMessage = "you can't enter blah if prop 2 equals 1";
return false;
}
if(model.Prop1 == "blah blah" && model.Prop2 == 2)
{
ErrorMessage = "you can't enter blah blah if prop 2 equals 2";
return false;
}
return true;
}
But when I do this I get an exception on the first time ErrorMessage is referenced "Cannot set property more than once.
Now I could split up my custom attribute into multiple cust开发者_C百科om attributes, but hoped there would be a way to do it in one, otherwise, I'll be repeating my "catch all" in each
//if this value is set, I don't want to do anything other checks
if (model.Prop3)
{
return true;
}
I've had a search already, but couldn't find anything, so apologies if I am missing anything obvious.
thanks in advance!
In MVC4 you can override IsValid to return different messages as the ValidationResult
public class StrongPasswordAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
if (value == null)
return new ValidationResult("Password is required");
var val = value.ToString();
if (!Regex.Match(val, @"^(?=.*[a-z]).{0,}$").Success)
{
return new ValidationResult("Password must contain at least one lower case letter");
}
if (!Regex.Match(val, @"^(?=.*[A-Z]).{0,}$").Success)
{
return new ValidationResult("Password must contain at least one UPPER case letter");
}
if (!Regex.Match(val, @"^(?=.*\d).{0,}$").Success)
{
return new ValidationResult("Password must contain at least one number");
}
return ValidationResult.Success;
}
}
Interesting question! I can think of two work-arounds to this. So not proper solutions based on what you want but they might help to re-use your code. Cant you create a CustomAttribute abstract class called MyCustomAttribute (or something) that overrides IsValid in the following way:
public override bool IsValid(object value)
{
var model = (MyObject) value;
//if this value is set, I don't want to do anything other checks
if (model.Prop3)
{
return true;
}
CustomValidate(model);
}
CustomValidate(MyObject model)
is your abstract method then, you can write multiple custom attribute classes that extend MyCustomAttribute and purely need to implement the validation logic for A particular scenario.
So you can have two classes:
public class BlahCustomAttribute : MyCustomAttribute
{
public override Boolean CustomValidate(MyObject obj)
{
if (model.Prop1 == "blah" && model.Prop2 == 1)
{
ErrorMessage = "you can't enter blah if prop 2 equals 1";
return false;
}
}
}
public class BlahBlahCustomAttribute : MyCustomAttribute
{
public override Boolean CustomValidate(MyObject obj)
{
if (model.Prop1 == "blah" && model.Prop2 == 1)
{
ErrorMessage = "you can't enter blah blah if prop 2 equals 1";
return false;
}
}
}
Hope this helps - not exactly what you wanted but will do the job and its clean as well.
The other solution is to comma-separate the error messages in the ErrorMessage property and handle it in the front-end (but I would go with the first approach).
精彩评论