What's the difference between using DataType Attribute and passing in a value of DataType.Phone and the Phone Attribute which inherits from DataType and automatically sets DataType.Phone?

Is there any difference between these two classes?

<!-- language: lang-cs --> <pre><code>class Person { <b>[DataType(DataType.PhoneNumber)]</b> public string PhoneNumber {get;set;} } </code></pre> <!-- language: lang-cs --> <pre><code>class Person { <b>[Phone]</b> public string PhoneNumber {get;set;} } </code></pre>

TLDR: [Phone] provides validation logic while [DataType] does not

The inheritance chain looks like this:

Attribute
ValidationAttribute
DataTypeAttribute
PhoneAttribute

So both are instances of ValidationAttribute, however both don't provide Validation out of the box. The DataType base class just provides the structure for assigning an enum DataType and leaves overriding the validation up to the caller

DataType - According to the Docs:

When you apply the DataTypeAttribute attribute to a data field you must do the following:

  • Issue validation errors as appropriate.

DataType - According to the Source Code:

<!-- language: lang-cs -->
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = false)]
public class DataTypeAttribute : ValidationAttribute
{
    /// <summary> Override of <see cref="ValidationAttribute.IsValid(object)" /> </summary>
    /// <remarks>This override always returns <c>true</c>.  Subclasses should override this to provide the correct result.</remarks>
    /// <param name="value">The value to validate</param>
    /// <returns>Unconditionally returns <c>true</c></returns>
    /// <exception cref="InvalidOperationException"> is thrown if the current attribute is ill-formed.</exception>
    public override bool IsValid(object value)
    {
        EnsureValidDataType();

        return true;
    }
 }

Aside: Since you are required to override IsValid, I'm not sure why .NET didn't mark the class and property as abstract to guarantee an implementation programmatically.

PhoneAttribute - Validation Logic

So if you do want to provide validation, and you're using .NET 4.5+ or .NET Core, you can use the [Phone] attribute, but the mechanism for validation has changed over time as well and also you might have a different set of rules on what constitutes valid input for your business process.

.NET Framework initially used the following regular expression:

<!-- language: lang-cs -->
const string pattern = @"^(\+\s?)?((?<!\+.*)\(\+?\d+([\s\-\.]?\d+)?\)|\d+)([\s\-\.]?(\(\d+([\s\-\.]?\d+)?\)|\d+))*(\s?(x|ext\.?)\s?\d+)?$";

But this was deprecated in .NET Framework 4.7.2 per this change description, likely due to injection/security concerns layed out in the Regular Expression Best Practices from unconstrained input.

If you want to continue using regex validation, you'd have to set the following in the configuration > appsettings section of your .config file:

<!-- language: lang-xml -->
<add key="dataAnnotations:dataTypeAttribute:disableRegEx" value="false"/>
        

The Test project includes a sample of what inputs should pass/fail according to PhoneAttributeTests.cs and here's a Regexr page if you want to test out matching input against the (deprecated) regular expression validation engine.


Here's some links for source code and documentation for different flavors of .NET:

<!-- language: lang-none --> <pre><code> | .NET Core | .NET Core 2.1 | .NET 4.7.2 | .NET | ------------------|-------------------|----------------|-----------------|----------------| <b>DataTypeAttribute</b> | <a href="https://github.com/dotnet/corefx/blob/v2.1.5/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/DataTypeAttribute.cs">github.com/dotnet</a> | <a href="https://source.dot.net/#System.ComponentModel.Annotations/System/ComponentModel/DataAnnotations/DataTypeAttribute.cs">source.dot.net</a> | <a href="https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/DataTypeAttribute.cs">referencesource</a> | <a href="https://learn.microsoft.com/en-us/dotnet/api/System.ComponentModel.DataAnnotations.DataTypeAttribute">docs.microsoft</a> | <b>PhoneAttribute</b> | <a href="https://github.com/dotnet/corefx/blob/v2.1.5/src/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/PhoneAttribute.cs">github.com/dotnet</a> | <a href="https://source.dot.net/#System.ComponentModel.Annotations/System/ComponentModel/DataAnnotations/PhoneAttribute.cs">source.dot.net</a> | <a href="https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/PhoneAttribute.cs">referencesource</a> | <a href="https://learn.microsoft.com/en-us/dotnet/api/System.ComponentModel.DataAnnotations.PhoneAttribute">docs.microsoft</a> | </code></pre>

Note: The current docs for [Phone] mistakenly remarks that the validation uses Regular Expressions, which has not been true since 4.7.2+ or anywhere in .NET core, so I've submitted this PR to update