I am trying to write a NotAttribute validator attribute for my MVC3 project. I want to use it like this:
[Not("00000000-0000-0000-0000-000000000000", typeof(Guid), ErrorMessage = "You must select a valid id.")]
public Guid ObjectId { get; set; }
Now I don’t want to tie the NotAttribute to a Guid, but the object should be parseable from a string; I want to look for a TryParse method first, then a Parse method; if both should fail, and the type is not already a string, I want to throw an error. So far, so good, no complications.
My class looks like this:
public class NotAttribute : ValidationAttribute, IClientValidatable
{
public Type PropertyType { get; set; }
public string NotEqualTo { get; private set; }
public bool IgnoreWhitespace { get; set; }
public bool CaseInsensitive { get; set; }
public NotAttribute(string notEqualTo)
{
NotEqualTo = notEqualTo;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (PropertyType == null) PropertyType = typeof(string);
if (PropertyType == typeof(string))
{
//this is the easy case. We can compare easy enough
var leftSide = value.ToStringOrEmpty();
var rightSide = NotEqualTo ?? string.Empty;
if (IgnoreWhitespace)
{
leftSide = leftSide.Trim();
rightSide = rightSide.Trim();
}
if (CaseInsensitive)
{
leftSide = leftSide.ToUpperInvariant();
rightSide = rightSide.ToUpperInvariant();
}
if (leftSide != rightSide) return null; // all is well
}
var tryParseMethod = PropertyType.GetMethod("TryParse",
Reflection.BindingFlags.Static | Reflection.BindingFlags.Public, null,
new Type[] {typeof(string), PropertyType.MakeByRefType()}, null);
//This is where I get lost
return base.IsValid(value, validationContext);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
throw new NotImplementedException();
}
}
I’m pretty sure my tryParseMethod will return a reference to the object method that I could theoretically invoke, but here’s where I run into problems.
How would I invoke it, passing in a type determined at runtime? This seems to be screaming for a generics implementation, but I have no idea where I could inject that here. Also, once I have the value I need to compare against the “not” value, I need to somehow cast it at runtime, which also screams for generics.
How can I make this work? Am I doing this completely the wrong way?
It’s a static method, so you should just be able to invoke it without needing an instance of a class of the type
PropertyTypeto invoke on (See the MSDN page). So, you can just callInvokeontryParseMethod.However, the
TryParsemethod itself will need an instance of a class of the typePropertyTypeas it’soutparameter though, so you’ll need to useSystem.Activator.CreateInstance()for that.So, presumably something like
will do the job.