views:

938

answers:

3

I have a customer class which has both PhoneNumber and Email properties. Using DataAnnotations I can decorate the properties with DataType validation attributes, but I cannot see what that is getting me.

For example:

 [DataType(DataType.PhoneNumber)]
 public string PhoneNumber {get; set;}

I have a unit test that assigned "1515999A" to this property. When I step through the validation runner the value is considered valid for a phone number. I would have thought this should be invalid.

I google'd around some but couldn't find a decent explanation of what the various enumerated DataTypes actually catch. Is there a worthwhile reference somewhere?

Edit:

Here are the guts of what I'm using for a validation runner...

    public virtual XLValidationIssues ValidateAttributes<TEntity>(TEntity entity)
    {
        var validationIssues = new XLValidationIssues();

        // Get list of properties from validationModel
        var props = entity.GetType().GetProperties();

        // Perform validation on each property
        foreach (var prop in props)
            ValidateProperty(validationIssues, entity, prop);

        // Return the list
        return validationIssues;
    }

    protected virtual void ValidateProperty<TEntity>(XLValidationIssues validationIssues, TEntity entity, PropertyInfo property)
    {
        // Get list of validator attributes
        var validators = property.GetCustomAttributes(typeof(ValidationAttribute), true);
        foreach (ValidationAttribute validator in validators)
            ValidateValidator(validationIssues, entity, property, validator);
    }

    protected virtual void ValidateValidator<TEntity>(XLValidationIssues validationIssues, TEntity entity, PropertyInfo property, ValidationAttribute validator)
    {
        var value = property.GetValue(entity, null);
        if (!validator.IsValid(value))
            validationIssues.Add(new XLValidationIssue(property.Name, value, validator.FormatErrorMessage(property.Name, value)));
    }
+1  A: 

The DataTypeAttribute is a ValidationAttribute. But it ALWAYS returns true... so it doesn't do any real validation.

(I know this is true for 3.5, I'm not sure if it's true for 4.0)

Joseph Daigle
I'm fairly new to MVC and was wondering if it always returns true should I care to set which type it is? How will this improve my code?
MIchael Grassman
The DataTypeAttribute wasn't designed for validation. Data annotations are just that: attributes which annotate the data. Some are used for validation, others are used to simply describe what the data represents.
Joseph Daigle
A: 

Maybe its because phone numbers can contain letters? wiki

RA
+2  A: 

I couldn't find much on the web about DataType.PhoneNumber, but I did find this:

http://forums.asp.net/p/1370546/2863383.aspx

In the RTM release, the DataType.EmailAddress is only used to mark the type of data for your own use.

I wanted to find out a bit more, so I pulled out Red Gate's .NET Reflector and started digging around.

Looking at the DataTypeAttribute class, Joseph Daigle is spot on -- each DataType attribute doesn't do any validation; is always returns true (i.e. "valid"). On some data types, some custom display string formatting is done. Phone numbers, however, are pretty much left untouched.

So, I looked into possible solutions to this problem. From what I've found, this looks like the best:

public class EvenNumberAttribute : ValidationAttribute
{
    public EvenNumberAttribute() : base(() => Resource1.EvenNumberError) { }
    public EvenNumberAttribute(string errorMessage) : base(() => errorMessage) { }

    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        if (value == null)
        {
            return ValidationResult.Success;
        }

        int convertedValue;
        try
        {
            convertedValue = Convert.ToInt32(value);
        }
        catch (FormatException)
        {
            return new ValidationResult(Resource1.ConversionError);
        }

        if (convertedValue % 2 == 0)
        {
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }
    }
}

Of course, that validates whether a number is odd or even. You could write a custom validation attribute for PhoneNumber, Email, etc. that actually does validation.

Doug