EmailAddress DataAnnotation 在 View 上标记为有效但 ModelState.IsValid = false?

Posted

技术标签:

【中文标题】EmailAddress DataAnnotation 在 View 上标记为有效但 ModelState.IsValid = false?【英文标题】:EmailAddress DataAnnotation marking as valid on View but ModelState.IsValid = false? 【发布时间】:2017-09-16 12:10:52 【问题描述】:

我正在使用 MVC5 并尝试验证表单。

当我在字段中插入无效的电子邮件地址时,它会显示错误消息

如果我插入 a@a(这是一个有效的电子邮件地址),则前端验证通过,但在后端,我的 ModelState 在 E-mail 字段中显示错误,说明这是无效的。

如果我插入 a@a.com,验证双方都会通过!

注意:与“电子邮件验证不适用于 MVC”相关的其他 SO 答案的很大一部分,解决方案是使用我已经在使用的 EmailAddress 属性。

查看

@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>

型号

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; 

控制器

public JsonResult EnviarMensagemContato(ModelContainer model)

    try
    
        if (ModelState.IsValid)
        
            //zalgo
         
    

【问题讨论】:

您的视图模型似乎没有 EmailAddress 属性。 @qamar 它有,但 asp.net 出于某种原因将数据注释连接在一行中,即:[required(..), maxlength(..)] 而不是单独的行。它在代码上。问候” a@a 不是有效的电子邮件地址。作为旁注,您可以看到属性 here 使用的正则表达式 【参考方案1】:

我假设您在 ASP.NET MVC 项目中使用默认的 jQuery Validation 库。如果是这种情况,问题就在于用于验证电子邮件的正则表达式在 jQuery Validation 库和 EmailAddressAttribute 中不同,属性更严格。我的建议是覆盖 jQuery Validation 电子邮件方法,如下所示:

$.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);

正则表达式直接取自EmailAddressAttribute 源代码here。如果您更喜欢允许不带 TLD 的电子邮件(例如 user@localhost),您可以编写自己的属性,如 in this answer 讨论的那样,并从 jQuery Validation 库中放入正则表达式。这样,您将拥有相同的验证结果客户端和服务器端。

【讨论】:

【参考方案2】:
    [Required(ErrorMessage = "The Email address is required")]
    [RegularExpression(RegularExpression.RegexEmail, ErrorMessage = "Invalid Email address")]
    public string Email  get; set; 

在 RegularExpression.cs 文件中包含

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

【讨论】:

【参考方案3】:

我不认为 a@a 是一个有效的电子邮件地址,或者如果是,我认为属性不会考虑它。

经过测试,如果我输入 a@a,我会收到客户端验证错误。我不输入 a@a.a

如果您需要此类电子邮件有效,您可以使用自己的正则表达式。

【讨论】:

【参考方案4】:

如果您需要细粒度的控制并让您的代码在您面前透明,我建议您不要依赖 HTML 助手来绘制您的控件并为您在客户端和服务器端执行验证。

我将使用以下常规 exp 作为 mvc 模型属性。

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

BusinessRules.Email 在哪里

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

在客户端验证中,您只能根据需要确保电子邮件不为空。最后,客户端验证不如服务器端验证重要,因为它很容易被欺骗。

【讨论】:

【参考方案5】:

像下面的代码一样一次表示一个数据注释是一种很好的做法,这也可能有助于解决您的错误。

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

【讨论】:

【参考方案6】:

有两个独立的控制点。如果您使用正确的比较一次,则不必再次检查该值以供以后使用。然后,使用正则表达式将解决问题。

【讨论】:

以上是关于EmailAddress DataAnnotation 在 View 上标记为有效但 ModelState.IsValid = false?的主要内容,如果未能解决你的问题,请参考以下文章

Validator EmailAddress可以验证一组电子邮件

获取 r_liteprofile 和 r_emailaddress - api.linkedin.com/v2

Django REST EmailAddress 匹配查询不存在

对ViewModel自定义约束

nameid-format:emailAddress 在使用电子邮件作为 nameid 格式时使用。当使用用户名作为 namid 字段时,正确的 nameid 格式是啥

urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress 是有效的 NameID 格式吗?