EmailAttribute is not validating correctly in a ViewModel from ASP.NET Core

Matthew picture Matthew · Jun 3, 2016 · Viewed 7.7k times · Source

This is a field located in my viewmodel:

[Required(ErrorMessage = "Email is missing."), EmailAddress(ErrorMessage = "Email is not valid.")]
public string Email { get; set; }

(EmailAddress is from the EmailAddressAttribute.EmailAddressAttribute() type)
This is the relevant part from the HTML:

<div>
    <label for="inputEmail">EMAIL</label>
    <input id="inputEmail" ng-model="email" asp-for="Email" class="form-control" />
</div>
<div>
    <span asp-validation-for="Email" class="text-danger"></span>
</div>

When I type myemail in the email text box, it will say

Email is invalid

However, when typing myemail@email, it will be viewed as correct by the view-model (only on the front-end).

public async Task<JsonResult> Register([FromForm]VisitViewModel vm)

Casting like this properly puts the ModelState on invalid and rejects the email, so that part is okay.

According to this answer though, the frontend should indicate this as invalid

Can anybody explain what is happening here? I'm at an absolute loss.

Answer

Will Ray picture Will Ray · Jul 15, 2016

There are inconsistencies in the way emails are validated between client and server.

Client side

jQuery Validation uses a regular expression defined in the HTML standard. According to that expression, email@email is a valid email address.

Server side

The .Net EmailAddressAttribute has it's own regular expression, which you can find here. According that that expression, email@email is an invalid email address.

But it gets even more confusing! If you're creating a .Net Core app, targeting cross platform uses the CoreFX version of the attribute which doesn't appear to use a regular expression at all. According to that method, email@email is a valid email address.

You see it for yourself by switching around values in the project.json of a Core Console App:

public static void Main(string[] args)
{
    var attr = new EmailAddressAttribute();
    var email = "email@email";
    var isValid = attr.IsValid(email); // false with "net452", true with "netcoreapp1.0"
}

What you can do

The quickest fix that I can think of would be to change the regular expression in the jQuery Validate email method to match the one from .Net, or create your own validation method to add to it which checks for this particular case.

You can also just fallback on returning errors from the server which would show them a validation message for whatever is wrong with the ModelState. It wouldn't be a real-time error but they would still get a nice message to deal with the improper email.