RequiredAttribute 和 AllowEmptyString=true ASP.NET MVC 3 非侵入式验证

RequiredAttribute with AllowEmptyString=true in ASP.NET MVC 3 unobtrusive validation

提问人:UserControl 提问时间:6/22/2011 更新时间:11/15/2013 访问量:29636

问:

如果我的视图模型中有声明,则验证总是在空输入上触发。我找到了这篇文章,解释了为什么会发生这种情况。您知道是否有可用的修复程序吗?如果没有,你如何处理?[Required(AllowEmptyStrings = true)]

验证 asp.net-mvc-3 jquery-validate unobtrusive-validation

评论


答:

23赞 Jon Galloway 6/28/2011 #1

注意:我假设您有 AllowEmptyStrings = true,因为您还在 Web 场景之外使用视图模型;否则,在 Web 场景中拥有允许空字符串的 Required 属性似乎没有多大意义。

有三个步骤可以处理此问题:

  1. 创建添加该验证参数的自定义属性适配器
  2. 将适配器注册为适配器工厂
  3. 重写 jQuery 验证函数,以在存在该属性时允许空字符串

第 1 步:自定义属性适配器

我修改了 RequiredAttributeAdapter 以添加该逻辑:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace CustomAttributes
{
    /// <summary>Provides an adapter for the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> attribute.</summary>
    public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute>
    {
        /// <summary>Initializes a new instance of the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> class.</summary>
        /// <param name="metadata">The model metadata.</param>
        /// <param name="context">The controller context.</param>
        /// <param name="attribute">The required attribute.</param>
        public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
        }
        /// <summary>Gets a list of required-value client validation rules.</summary>
        /// <returns>A list of required-value client validation rules.</returns>
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var rule = new ModelClientValidationRequiredRule(base.ErrorMessage);
            if (base.Attribute.AllowEmptyStrings)
            {
                //setting "true" rather than bool true which is serialized as "True"
                rule.ValidationParameters["allowempty"] = "true";
            }

            return new ModelClientValidationRequiredRule[] { rule };
        }
    }
}

第2步。在您的 global.asax / Application_Start() 中注册此内容

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(typeof(RequiredAttribute),
          (metadata, controllerContext, attribute) => new CustomAttributes.RequiredAttributeAdapter(metadata,
            controllerContext, (RequiredAttribute)attribute)); 

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

第 3 步。重写 jQuery“required”验证函数

这是使用 jQuery.validator.addMethod() 调用完成的,添加我们的自定义逻辑,然后调用原始函数 - 您可以在此处阅读有关此方法的更多信息。如果在整个站点中使用它,则可能在从 _Layout.cshtml 引用的脚本文件中。下面是一个示例脚本块,您可以将其放入页面进行测试:

<script>
jQuery.validator.methods.oldRequired = jQuery.validator.methods.required;

jQuery.validator.addMethod("required", function (value, element, param) {
    if ($(element).attr('data-val-required-allowempty') == 'true') {
        return true;
    }
    return jQuery.validator.methods.oldRequired.call(this, value, element, param);
},
jQuery.validator.messages.required // use default message
);
</script>

评论

0赞 UserControl 6/28/2011
谢谢你的努力,乔恩!不幸的是,它对我不起作用,我仍然看到“字段为必填项”消息:(我仔细检查了您的代码是否使用 VS 和浏览器调试器执行,并且我没有任何可能干扰的自定义脚本或与验证相关的代码。我使用jQuery 1.4.1。这会是问题所在吗?
0赞 UserControl 6/28/2011
是的,你是对的,我需要 Web 场景之外的功能(我的应用程序服务层执行类似的验证检查以达到 DRY)。
0赞 Tz_ 6/29/2011
+1 这似乎是一个不错的解决方案,我想知道为什么它不起作用。但是,如果在 AllowEmptyStrings 的情况下适配器中不返回验证规则(空数组),也许可以简化它。然后,您可以省去客户端的魔术。然后,您还可以轻松检查输入中是否正确省略了必需的属性。如果它仍然不起作用,则应调试适配器代码,并查看是否正确调用它(如果注册正常)。
0赞 Jon Galloway 6/29/2011
这有“在我的机器上工作”的承诺;-)我列出的脚本块紧接在调用 /Scripts/jquery.validate.js 和 /Scripts/jquery.validate.unobtrusive.js 之后。我正在使用 jQuery 1.5.1 的新 MVC 3 项目。我将尝试发布示例项目,以便您可以进行比较。
0赞 Jon Galloway 7/2/2011
我很好奇 - 什么不起作用?它是 Javascript 参考吗?
16赞 Rick Arthur 9/9/2013 #2

我没有使用“Required”属性来修饰值,而是使用以下方法。我发现这是解决这个问题的最简单方法。

[显示格式 (ConvertEmptyStringToNull=false) ]

评论

0赞 Andy White 12/5/2013
我同意 - 这似乎是处理此问题的最简单方法。如果要允许空字符串,只需在保存之前在控制器中将 null 改回 “” 即可!
3赞 Mark Rucker 10/21/2015
美丽![必需]的这个缺点多年来一直让我在多个 asp.net 网站上感到恼火。(我现在同时使用 [Required(AllowEmptyStrings = true)、DisplayFormat(ConvertEmptyStringToNull=false)],效果很好。
0赞 AH. 12/3/2015
很好的答案。多谢。
0赞 Patrick Montelo 2/17/2016
+10 给 Rick 和 Mark,用于缓解 MVC 空字符串的痛苦,同时使用 DisplayFormat(ConvertEmptyStringToNull=false) 和 Required(AllowEmptyStrings = true)