Reputation: 17176
I want to write custom validation attribute and add additional member names which have validation errors to validation result. The thing is I want to generate member name dynamically based on property name and invalid match property index or key (I want to validate IEnumerables or IDictionaries) like Names[0]
, Names[1]
, Names[key]
etc. For example:
Model:
public class ModelClass
{
[ItemMaxLength(10)]
[Display(ResourceType = typeof(CategoriesRename), Name = "CategoryNamesFieldName")]
public IDictionary<string, string> Names { get; set; }
}
Attribute:
public class ItemMaxLengthAttribute : ValidationAttribute
{
private readonly int _maxLength = int.MaxValue;
public ItemMaxLengthAttribute(int maxLength)
{
_maxLength = maxLength;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
...
// I can get instance and it's type from validation context
var instance = validationContext.ObjectInstance; // which is instance of ModelClass
var instanceType = validationContext.ObjectType; //which is typeof(ModelClass)
var dispayName = validationContext.DisplayName; //which is value of Display attribute
...
}
}
So the main idea is (I don't like it ether) get current property been validated by it's DysplayName
attribute value (dispayName
). I'm kind'a stuck here for a while. Maybe is there some other way to get property info of the property which is validating?
P.S. I've already tried MemberName
property, as Alexandre Rondeau suggested, but the problem is that validationContext.MemberName = null
so it can't be used. Also MSDN says that this property represents an entity member name, not the name of a corresponding data field and I need the name of a corresponding data field.
Upvotes: 6
Views: 9182
Reputation: 389
You have to use validationContext.MemberName
property.
Example:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var userManager = validationContext.GetService<UserManager<ApplicationUser>>();
var findingTask = userManager.FindByEmailAsync((string)value);
findingTask.Wait();
var user = findingTask.Result;
return user == null
? ValidationResult.Success
: new ValidationResult("This email already in use", new string[] { validationContext.MemberName });
}
Upvotes: 0
Reputation: 2687
Using that code, both test passes, so the MemberName isn't null.
[TestClass]
public class RefectionInValidationTest
{
[TestMethod]
public void GivenAModelWithItemMaxAttributeOnFieldName_WhenValidating_ThenModelClassIsValid()
{
//Arange
var validModelClass = new ModelClass();
var validations = new Collection<ValidationResult>();
//Act
var isValid = Validator.TryValidateObject(validModelClass, new ValidationContext(validModelClass, null, null), validations, true);
//Assert
Assert.IsTrue(isValid);
}
[TestMethod]
public void GivenAModelWithItemMaxAttributeOnFieldNotName_WhenValidating_ThenModelClassIsInvalid()
{
//Arange
var invalidaModelClass = new InvalidModelClass();
var validations = new Collection<ValidationResult>();
//Act
var isValid = Validator.TryValidateObject(invalidaModelClass, new ValidationContext(invalidaModelClass, null, null), validations, true);
//Assert
Assert.IsFalse(isValid);
}
}
public class ModelClass
{
[ItemMaxLength(10)]
public IDictionary<string, string> Names { get; set; }
}
public class InvalidModelClass
{
[ItemMaxLength(10)]
public IDictionary<string, string> NotNames { get; set; }
}
public class ItemMaxLengthAttribute : ValidationAttribute
{
private readonly int _maxLength = int.MaxValue;
public ItemMaxLengthAttribute(int maxLength)
{
_maxLength = maxLength;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propretyInfo = validationContext.ObjectType.GetProperty(validationContext.MemberName);
if (propretyInfo.Name == "Names")
return ValidationResult.Success;
return new ValidationResult("The property isn't 'Names'");
}
}
Upvotes: 5