如何使用 DataAnnotations 处理 ASP.NET MVC 2 中的布尔值/复选框?

Posted

技术标签:

【中文标题】如何使用 DataAnnotations 处理 ASP.NET MVC 2 中的布尔值/复选框?【英文标题】:How to handle Booleans/CheckBoxes in ASP.NET MVC 2 with DataAnnotations? 【发布时间】:2011-01-15 18:07:31 【问题描述】:

我有一个这样的视图模型:

public class SignUpViewModel

    [Required(ErrorMessage = "Bitte lesen und akzeptieren Sie die AGB.")]
    [DisplayName("Ich habe die AGB gelesen und akzeptiere diese.")]
    public bool AgreesWithTerms  get; set; 

视图标记代码:

<%= html.CheckBoxFor(m => m.AgreesWithTerms) %>
<%= Html.LabelFor(m => m.AgreesWithTerms)%>

结果:

不执行验证。到目前为止没关系,因为 bool 是一种值类型,并且永远不会为空。但即使我让 AgreesWithTerms 为空,它也不会工作,因为编译器会喊

“模板只能用于字段访问、属性访问、一维数组索引或单参数自定义索引器表达式。”

那么,处理这个问题的正确方法是什么?

【问题讨论】:

【参考方案1】:

我的解决方案如下(和已经提交的答案差别不大,但我相信命名更好):

/// <summary>
/// Validation attribute that demands that a boolean value must be true.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute

    public override bool IsValid(object value)
    
        return value != null && value is bool && (bool)value;
    

然后你可以在你的模型中这样使用它:

[MustBeTrue(ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms  get; set; 

【讨论】:

+1:搜索,找到帖子,选择最佳答案(你是对的,你的被评为最佳答案),剪切,粘贴,刷新,问题解决。不到 2 分钟...甜 这似乎不适用于我的 vanilla MVC 2 项目...已知问题? 也是一个很好的例子,如果它似乎对你不起作用,它似乎要等到你的所有其他验证([必需]等......)都为真后再“触发” . 第一个检查(值!= null)甚至可以省略:) 不能在客户端工作?这与仅添加 [Range(1, 1)] 注释相同。【参考方案2】:

我将为服务器端和客户端创建一个验证器。使用 MVC 和不显眼的表单验证,只需执行以下操作即可实现:

首先,在您的项目中创建一个类来执行服务器端验证,如下所示:

public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable

    public override bool IsValid(object value)
    
        if (value == null) return false;
        if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");
        return (bool)value == true;
    

    public override string FormatErrorMessage(string name)
    
        return "The " + name + " field must be checked in order to continue.";
    

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    
        yield return new ModelClientValidationRule
        
            ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage,
            ValidationType = "enforcetrue"
        ;
    

然后,在模型中注释适当的属性:

[EnforceTrue(ErrorMessage=@"Error Message")]
public bool ThisMustBeTrue get; set; 

最后,通过将以下脚本添加到您的视图来启用客户端验证:

<script type="text/javascript">
    jQuery.validator.addMethod("enforcetrue", function (value, element, param) 
        return element.checked;
    );
    jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>

注意:我们已经创建了一个方法GetClientValidationRules,它将注释从我们的模型推送到视图。

【讨论】:

我终于找到了可行的解决方案!其他的不完整(有时JS部分遗漏,有时是错误的)。非常感谢。 @AlexanderProkofyev - 很高兴你发现它有用!我发现了同样的事情,所以一旦我有了解决方案,我想我会发布一个完整的答案。 可能值得注意的是:如果想将 JS 与视图分开,调用 addMethod 和 addBool 函数来设置客户端验证在 document.ready 函数内部不起作用。 太棒了!另外值得注意的是 - 如果它似乎不起作用,则必须通过所有其他验证才能验证此验证。 这应该是公认的答案,上面的一个和接受的一个在客户端不起作用【参考方案3】:

我通过创建自定义属性得到它:

public class BooleanRequiredAttribute : RequiredAttribute 

    public override bool IsValid(object value)
    
        return value != null && (bool) value;
    

【讨论】:

+1 用于发布您的解决方案,但我仍然认为“必需”是错误的名称。我会叫它BooleanRequireTrueAttribute 什么的。 是的,我同意你的看法。我将它重命名为 BooleanRequireToBeTrueAttribute【参考方案4】:

这可能是一个“hack”,但您可以使用内置的 Range 属性:

[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms  get; set; 

唯一的问题是“警告”字符串会显示“FIELDNAME 必须介于 True 和 true 之间”。

【讨论】:

对我来说很好,我不认为它是一个黑客 您可能需要添加客户端代码验证才能使其正常工作。 &lt;script&gt; var defaultRangeValidator = $.validator.methods.range; $.validator.methods.range = function(value, element, param) if(element.type === 'checkbox') return element.checked; else return defaultRangeValidator.call(this, value, element, param); &lt;/script&gt;Read here for more info 客户端不起作用,勾选复选框时显示错误消息【参考方案5】:
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember  get; set; 

【讨论】:

不错 :) 但我怀疑这在服务器端不起作用?【参考方案6】:

这里的“必需”是错误的验证。您想要类似于“必须具有真实值”的内容,这与“必需”不同。使用类似的东西怎么样:

[RegularExpression("^true")]

?

【讨论】:

如果布尔值必须始终为 / 必须为真,那么在您的代码中甚至没有必要。如果Required 属性有助于DB 级别的“NOT NULL”语句,则不需要它,因为保证您具有真值或假值。 @Chris,它将在您的编辑模型上,但不在您的实体上。通常,您不应直接绑定到实体。 @Craig,同意不直接绑定。但是,如果您的域模型对象(实体)有一个属性必须始终为真,那么它就不是一个有用的属性,对吧? 对,但这不是他在这里提议的。 @Peter:检查 POST 包含的内容。写一个比我第一个猜测更好的正则表达式。【参考方案7】:

我的解决方案是这个布尔值的简单自定义属性:

public class BooleanAttribute : ValidationAttribute

    public bool Value
    
        get;
        set;
    

    public override bool IsValid(object value)
    
        return value != null && value is bool && (bool)value == Value;
    

然后你可以在你的模型中这样使用它:

[Required]
[Boolean(Value = true, ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms  get; set; 

【讨论】:

【参考方案8】:

我只是充分利用现有解决方案,并将其组合成一个允许服务器端和客户端验证的单一答案。

应用于对属性建模以确保布尔值必须为真:

/// <summary>
/// Validation attribute that demands that a <see cref="bool"/> value must be true.
/// </summary>
/// <remarks>Thank you <c>http://***.com/a/22511718</c></remarks>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable

    /// <summary>
    /// Initializes a new instance of the <see cref="MustBeTrueAttribute" /> class.
    /// </summary>
    public MustBeTrueAttribute()
        : base(() => "The field 0 must be checked.")
    
    

    /// <summary>
    /// Checks to see if the given object in <paramref name="value"/> is <c>true</c>.
    /// </summary>
    /// <param name="value">The value to check.</param>
    /// <returns><c>true</c> if the object is a <see cref="bool"/> and <c>true</c>; otherwise <c>false</c>.</returns>
    public override bool IsValid(object value)
    
        return (value as bool?).GetValueOrDefault();
    

    /// <summary>
    /// Returns client validation rules for <see cref="bool"/> values that must be true.
    /// </summary>
    /// <param name="metadata">The model metadata.</param>
    /// <param name="context">The controller context.</param>
    /// <returns>The client validation rules for this validator.</returns>
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    
        if (metadata == null)
            throw new ArgumentNullException("metadata");
        if (context == null)
            throw new ArgumentNullException("context");

        yield return new ModelClientValidationRule
            
                ErrorMessage = FormatErrorMessage(metadata.DisplayName),
                ValidationType = "mustbetrue",
            ;
    

为了使用不显眼的验证而包含的 JavaScript。

jQuery.validator.addMethod("mustbetrue", function (value, element) 
    return element.checked;
);
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");

【讨论】:

【参考方案9】:

对于那些在客户端验证时遇到困难的人(以前是我):确保你也有

    包含 在视图中的表单之前 使用 创建了一个 DataAnnotationsModelValidator,它返回具有自定义验证类型的规则 在 Global.Application_Start 中注册了派生自 DataAnnotationsModelValidator 的类

http://www.highoncoding.com/Articles/729_Creating_Custom_Client_Side_Validation_in_ASP_NET_MVC_2_0.aspx

这是一个很好的教程,但错过了第 4 步。

【讨论】:

【参考方案10】:

正确的做法是检查类型!

[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms  get; set; 

【讨论】:

【参考方案11】:

在这里找到了更完整的解决方案(服务器端和客户端验证):

http://blog.degree.no/2012/03/validation-of-required-checkbox-in-asp-net-mvc/#comments

【讨论】:

【参考方案12】:

加上[RegularExpression]就够了:

[DisplayName("I accept terms and conditions")]
[RegularExpression("True", ErrorMessage = "You must accept the terms and conditions")]
public bool AgreesWithTerms  get; set; 

注意 - “真”必须以大写 T 开头

【讨论】:

以上是关于如何使用 DataAnnotations 处理 ASP.NET MVC 2 中的布尔值/复选框?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 DataAnnotations 来检查一个属性只匹配一个字符串数组

如何覆盖DataAnnotations必需标记以允许条件客户端验证

使用 DataAnnotations 比较两个模型属性

如何将 DataAnnotations ErrorMessageResourceName 与自定义资源解决方案一起使用

DataAnnotations - InverseProperty Attribute:

ASP.NET-表单验证-DataAnnotations