1

I'm using MVC5 and trying to validate a form.

When I insert an invalid email address on the field, it shows the error message

enter image description here

If I insert a@a (which is a valid email address), the front-end validation pass, but on back end, my ModelState shows an error on the E-mail field, telling that is invalid.

If I insert a@a.com, both validation sides pass!

Note: Great part of the other SO answers related to "email validation not working on MVC", the solution was to use the EmailAddress attribute, which i'm already using.

View

@using (Ajax.BeginForm("EnviarMensagemContato", "home", new AjaxOptions { HttpMethod = "POST", OnBegin = "showLoading", OnComplete = "showJsonModalMessage" }, new { @id = "contact-form" }))
{
    @Html.AntiForgeryToken()
    <div class="col-md-6 lateral-division">
        <div class="form-group">
            @Html.TextBoxFor(m => m.ContatoViewModel.Nome, new { @class = "form-control required", placeholder = "nome" })
            @Html.ValidationMessageFor(m => m.ContatoViewModel.Nome)
        </div>
        <div class="form-group">
            @Html.TextBoxFor(m => m.ContatoViewModel.EmailAddress, new { @class = "form-control required", placeholder = "email" })
            @Html.ValidationMessageFor(m => m.ContatoViewModel.EmailAddress)
        </div>
        <div class="form-group">
            @Html.TextAreaFor(m => m.ContatoViewModel.Mensagem, 4, 4, new { @class = "form-control required", placeholder = "mensagem" })
            @Html.ValidationMessageFor(m => m.ContatoViewModel.Mensagem)
        </div>
    </div>
    <div class="btn-group pull-right btn-send-message">
    <input type="submit" value="enviar" id="enviar-mensagem" class="btn btn-default" />
    </div>
}

Model

public class ContatoViewModel
{
    [Required(ErrorMessage="campo obrigatório"), 
    Display(Name = "nome")]
    public String Nome { get; set; }

    [Required(ErrorMessage = "campo obrigatório"), 
    Display(Name = "nome"), MaxLength(254,ErrorMessage="email inválido"), 
    EmailAddress(ErrorMessage="email inválido")]
    public String EmailAddress { get; set; }

    [Required(ErrorMessage = "campo obrigatório"), 
    Display(Name = "nome"), MaxLength(500, ErrorMessage = "maximo de 500 caracteres")]
    public String Mensagem { get; set; }
}

Controller

public JsonResult EnviarMensagemContato(ModelContainer model)
{
    try
    {
        if (ModelState.IsValid)
        {
            //zalgo
        } 
    }
}
Shahzad
  • 1,315
  • 2
  • 22
  • 42
  • your view model does not seem to have the EmailAddress attribute. – qamar Apr 20 '17 at 03:30
  • @qamar it has, but asp.net for some reason is concatenating the dataannotations in a single line, i.e: `[required(..), maxlength(..)]` instead of separate lines. It's on the code. Regards" – undefined is our god Apr 20 '17 at 03:33
  • `a@a` is not a valid email address. And as a side note, you can see the regex that is used by the attribute [here](https://github.com/Microsoft/referencesource/blob/master/System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs) –  Apr 20 '17 at 04:04

6 Answers6

2

I presume you're using the default jQuery Validation library in an ASP.NET MVC project. If that's the case, the problem resides in the fact that the regular expression used to validate an email is different in the jQuery Validation library and the EmailAddressAttribute, with the attribute being more strict. My suggestion would be to override the jQuery Validation email method as follows:

$.validator.methods.email = function (value, element) { 
     return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/.test(value);
}

The regular expression is taken directly from the EmailAddressAttribute source code here. If you prefer to allow emails without a TLD (like user@localhost), you could write your own attribute as discussed in this answer and put the regular expression from the jQuery Validation library. This way you would have the same validation result client and server side.

Community
  • 1
  • 1
ebejko
  • 36
  • 2
1
    [Required(ErrorMessage = "The Email address is required")]
    [RegularExpression(RegularExpression.RegexEmail, ErrorMessage = "Invalid Email address")]
    public string Email { get; set; }

In RegularExpression.cs file include

    /// <summary>
    /// Regular expression for email
    /// </summary>
    public const string RegexEmail = @"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}";
0

I don't think a@a is a valid email address, or if it is, I don't think the Attribute takes it into account.

Having tested this, if I enter a@a I get client side validation error. I don't if I enter a@a.a

If you need this kind of email to be valid you can probably use your own regex expression.

Etienne
  • 1,058
  • 11
  • 22
0

If you need fine grained control and have your code transparent in front of you, i recommend you dont rely on HTML helpers to draw your controls and perform the validation on client side and server side for you.

I would use the following regular exp as mvc model attribute.

[Required]
[RegularExpression(BusinessRules.Email,ErrorMessage = Messages.EmailNotValid)]
public string LoginEmail { get; set; }

Where BusinessRules.Email is

public const string Email = "^[\\w!#$%&'*+\\-/=?\\^_`{|}~]+(\\.[\\w!#$%&'*+\\-/=?\\^_`{|}~]+)*@((([\\-\\w]+\\.)+[a-zA-Z]{2,4})|(([0-9]{1,3}\\.){3}[0-9]{1,3}))$";

On the client side validation, you can only make sure that email is not empty if you want. At the end, client side validation is not as important as server side validation since it can be easily spoofed.

Houssam Hamdan
  • 888
  • 6
  • 15
0

It is good practice to represent you data annotations one at a time like the following code, this may also help with your error.

    [Required(ErrorMessage="campo obrigatório")] 
    [Display(Name = "nome")]
    public String Nome { get; set; }
Plumbus
  • 31
  • 1
  • 1
  • 6
0

There are two separate control points. If you use the correct comparison once, you don't have to check the value again for later usage. Then, using regular expression will solve the problem.

Tunahan
  • 303
  • 4
  • 22