52

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

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 可以为空,它也不会起作用,因为编译器会喊

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

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

4

12 回答 12

98

My Solution is as follows (it's not much different to the answers already submitted, but I believe it's named better):

/// <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;
    }
}

Then you can use it like this in your model:

[MustBeTrue(ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
于 2010-04-25T23:31:46.287 回答
51

I would create a validator for both Server AND Client side. Using MVC and unobtrusive form validation, this can be achieved simply by doing the following:

Firstly, create a class in your project to perform the server side validation like so:

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"
        };
    }
}

Following this, annotate the appropriate property in your model:

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

And Finally, enable client side validation by adding the following script to your View:

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

Note: We already created a method GetClientValidationRules which pushes our annotation to the view from our model.

于 2012-01-27T16:03:39.927 回答
19

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

public class BooleanRequiredAttribute : RequiredAttribute 
{
    public override bool IsValid(object value)
    {
        return value != null && (bool) value;
    }
}
于 2010-02-11T15:17:14.743 回答
7

This might be a "hack" but you can use the built in Range attribute:

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

The only problem is the "warning" string will say "The FIELDNAME must be between True and true".

于 2013-06-03T21:55:44.073 回答
7
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
于 2014-03-05T14:08:40.463 回答
4

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

[RegularExpression("^true")]

?

于 2010-02-11T15:06:25.250 回答
3

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

public class BooleanAttribute : ValidationAttribute
{
    public bool Value
    {
        get;
        set;
    }

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

Then you can use it like this in your model:

[Required]
[Boolean(Value = true, ErrorMessage = "You must accept the terms and conditions")]
[DisplayName("Accept terms and conditions")]
public bool AcceptsTerms { get; set; }
于 2010-04-06T17:54:41.983 回答
3

I'm just taking the best of the existing solutions and putting it together into a single answer that allows for both server side and client side validation.

The to apply to model a properties to ensure a bool value must be true:

/// <summary>
/// Validation attribute that demands that a <see cref="bool"/> value must be true.
/// </summary>
/// <remarks>Thank you <c>http://stackoverflow.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",
            };
    }
}

The JavaScript to include to make use of unobtrusive validation.

jQuery.validator.addMethod("mustbetrue", function (value, element) {
    return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
于 2014-03-19T16:07:43.160 回答
2

For people who are having trouble getting this working for validation on the client side (formerly me): make sure you have also

  1. Included <% Html.EnableClientValidation(); %> before the form in the view
  2. Used <%= Html.ValidationMessage or Html.ValidationMessageFor for the field
  3. Created a DataAnnotationsModelValidator which returns a rule with a custom validation type
  4. Registered the class deriving from DataAnnotationsModelValidator in the Global.Application_Start

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

is a good tutorial on doing this, but misses step 4.

于 2011-04-28T17:17:37.560 回答
2

The proper way to do this is to check the type!

[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
于 2016-01-18T20:28:03.483 回答
1

Found a more complete solution here (both server and client side validation):

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

于 2012-10-10T03:09:33.593 回答
1

It's enough to add [RegularExpression]:

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

Note - "True" must start with capital T

于 2015-05-07T11:57:37.733 回答