MVC Model require true

asp.net MvcData Annotations

asp.net Mvc Problem Overview


Is there a way through data annotations to require that a boolean property be set to true?

public class MyAwesomeObj{
    public bool ThisMustBeTrue{get;set;}
}

asp.net Mvc Solutions


Solution 1 - asp.net Mvc

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.

If using resource files to supply the error message for internationalization, remove the FormatErrorMessage call (or just call the base) and tweak the GetClientValidationRules method like so:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
    string errorMessage = String.Empty;
    if(String.IsNullOrWhiteSpace(ErrorMessage))
    {
        // Check if they supplied an error message resource
        if(ErrorMessageResourceType != null && !String.IsNullOrWhiteSpace(ErrorMessageResourceName))
        {
            var resMan = new ResourceManager(ErrorMessageResourceType.FullName, ErrorMessageResourceType.Assembly);
            errorMessage = resMan.GetString(ErrorMessageResourceName);
        }
    }
    else
    {
        errorMessage = ErrorMessage;
    }

    yield return new ModelClientValidationRule
    {
        ErrorMessage = errorMessage,
        ValidationType = "enforcetrue"
    };
}

Solution 2 - asp.net Mvc

I know this is an older post but wanted to share a simple server side way to do this. You create a public property set to true and compare your bool to that property. If your bool is not checked (by default false) the form will not validate.

public bool isTrue
{ get { return true; } }

[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare("isTrue", ErrorMessage = "Please agree to Terms and Conditions")]
public bool AgreeTerms { get; set; }

Razor code

@Html.CheckBoxFor(m => Model.AgreeTerms, new { id = "AgreeTerms", @checked = "checked" })
<label asp-for="AgreeTerms" class="control-label"></label>
<a target="_blank" href="/Terms">Read</a>
<br />
@Html.ValidationMessageFor(model => model.AgreeTerms, "", new { @class = "text-danger" })
@Html.HiddenFor(x => Model.isTrue)

Solution 3 - asp.net Mvc

You could create your own validator:

public class IsTrueAttribute : ValidationAttribute
{
    #region Overrides of ValidationAttribute

    /// <summary>
    /// Determines whether the specified value of the object is valid. 
    /// </summary>
    /// <returns>
    /// true if the specified value is valid; otherwise, false. 
    /// </returns>
    /// <param name="value">The value of the specified validation object on which the <see cref="T:System.ComponentModel.DataAnnotations.ValidationAttribute"/> is declared.
    ///                 </param>
    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;
    }

    #endregion
}

Solution 4 - asp.net Mvc

I tried several solutions but none of them worked completely for me to get both client and server side validation. So what I did in my MVC 5 application to get it to work:

In your ViewModel (for server side validation):

public bool IsTrue => true;

[Required]
[Display(Name = "I agree to the terms and conditions")]
[Compare(nameof(IsTrue), ErrorMessage = "Please agree to Terms and Conditions")]
public bool HasAcceptedTermsAndConditions { get; set; }

In your Razor page (for client side validation):

<div class="form-group">
   @Html.CheckBoxFor(m => m.HasAcceptedTermsAndConditions)
   @Html.LabelFor(m => m.HasAcceptedTermsAndConditions)
   @Html.ValidationMessageFor(m => m.HasAcceptedTermsAndConditions)

   @Html.Hidden(nameof(Model.IsTrue), "true")
</div>

Solution 5 - asp.net Mvc

I would just like to direct people to the following Fiddle: https://dotnetfiddle.net/JbPh0X

The user added [Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")] to their boolean property which causes server side validation to work.

In order to also have the client side validation working, they added the following script:

// extend jquery range validator to work for required checkboxes
var defaultRangeValidator = $.validator.methods.range;
$.validator.methods.range = function(value, element, param) {
    if(element.type === 'checkbox') {
        // if it's a checkbox return true if it is checked
        return element.checked;
    } else {
        // otherwise run the default validation function
        return defaultRangeValidator.call(this, value, element, param);
    }
}

Solution 6 - asp.net Mvc

Just check to see whether its string representation is equal to True:

[RegularExpression("True")]
public bool TermsAndConditions { get; set; }

Solution 7 - asp.net Mvc

You could either create your own attribute or use the CustomValidationAttribute.

This is how you would use the CustomValidationAttribute:

[CustomValidation(typeof(BoolValidation), "ValidateBool")]

where BoolValidation is defined as:

public class BoolValidation
{
  public static ValidationResult ValidateBool(bool boolToBeTrue)
  {
    if (boolToBeTrue)
    {
      return ValidationResult.Success;
    }
    else
    {
      return new ValidationResult(
          "Bool must be true.");
    }
  }

Solution 8 - asp.net Mvc

[Required] attribute stands for requiring any value - it can be either true or false. You'd have to use another validation for that.

Solution 9 - asp.net Mvc

Following up on the post by ta.speot.is and the comment from Jerad Rose:

The given post will not work client-side with unobtrusive validation. This should work in both camps (client & server):

[RegularExpression("(True|true)")]
public bool TermsAndConditions { get; set; }

Solution 10 - asp.net Mvc

For ASP.NET Core MVC here is client and server validation, based on dazbradbury's solution

public class EnforceTrueAttribute : ValidationAttribute, IClientModelValidator
{
    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;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        MergeAttribute(context.Attributes, "data-val", "true");
        var errorMessage = ErrorMessage ?? 
            $"The value for field {context.ModelMetadata.GetDisplayName()} must be true.";
        MergeAttribute(context.Attributes, "data-val-enforcetrue", errorMessage);
    }

    private void MergeAttribute(IDictionary<string, string> attributes,
        string key,
        string value)
    {
        if (attributes.ContainsKey(key))
        {
            return;
        }
        attributes.Add(key, value);
    }
}

And then on the client:

$.validator.addMethod("enforcetrue", function (value, element, param) {
    return element.checked;
});

$.validator.unobtrusive.adapters.addBool("enforcetrue");

Then usage is:

[EnforceTrue(ErrorMessage = "Please tick the checkbox")]
public bool IsAccepted { get; set; }

Solution 11 - asp.net Mvc

.NET Core MVC - Required Checkbox with Data Annotations

public class MyModel
{
	[Display(Name = "Confirmation")]
    [Range(typeof(bool), "true", "true", ErrorMessage = "Please check the Confirmation checkbox.")]
    public bool IsConfirmed { get; set; }	
}

<div class="custom-control custom-checkbox col-10">
    <input type="checkbox" asp-for="IsConfirmed" class="custom-control-input" />
    <label class="custom-control-label" for="IsConfirmed">
        "By clicking 'submit', I confirm."
    </label>
    <span asp-validation-for="IsConfirmed" class="text-danger"></span>
</div>

<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>

<script type="text/javascript">
    $(document).ready(function () {
        // extend range validator method to treat checkboxes differently
        var defaultRangeValidator = $.validator.methods.range;
        $.validator.methods.range = function (value, element, param) {
            if (element.type === 'checkbox') {
                // if it's a checkbox return true if it is checked
                return element.checked;
            } else {
                // otherwise run the default validation function
                return defaultRangeValidator.call(this, value, element, param);
            }
        }
    });
</script>

Solution 12 - asp.net Mvc

I don't know of a way through DataAnnotations, but this is easily done in your controller.

public ActionResult Add(Domain.Something model)
{

	if (!model.MyCheckBox)
		ModelState.AddModelError("MyCheckBox", "You forgot to click accept");

	if (ModelState.IsValid) {
		//'# do your stuff
	}

}

The only other option would be to build a custom validator for the server side and a remote validator for the client side (remote validation is only available in MVC3+)

Solution 13 - asp.net Mvc

Do you have the appropriate items set up in the web.config?

That could cause the validation not to work.

You can also try to create a custom validation attribute (since [Required] only cares whether or not it exists, and you care about the value):

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class RequiredTrueAttribute : ValidationAttribute
{
    // Internal field to hold the mask value.
    readonly bool accepted;

    public bool Accepted
    {
        get { return accepted; }
    }

    public RequiredTrueAttribute(bool accepted)
    {
        this.accepted = accepted;
    }

    public override bool IsValid(object value)
    {
        bool isAccepted = (bool)value;
        return (isAccepted == true);
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture,
          ErrorMessageString, name, this.Accepted);
    }
}

Then, usage:

[RequiredTrue(ErrorMessage="{0} requires acceptance to continue.")]
public bool Agreement {get; set;}

From here.

Solution 14 - asp.net Mvc

This is what worked for me. Nothing else did. Mvc 5:

Model

public string True
{
  get
  {
    return "true";
  }
}

[Required]
[Compare("True", ErrorMessage = "Please agree to the Acknowlegement")]
public bool Acknowlegement { get; set; }

View

  @Html.HiddenFor(m => m.True)
  @Html.EditorFor(model => model.Acknowlegement, new { htmlAttributes = Model.Attributes })
  @Html.ValidationMessageFor(model => model.Acknowlegement, "", new { @class = "text-danger" })

enter image description here

enter image description here

Solution 15 - asp.net Mvc

I tried to use fields.cage's answer and it didn't quite work for me, but something simpler did, and I'm not sure exactly why (different Razor version, maybe?), but all I had to do was this:

[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "Agreement required.")]
[Display(Name = "By clicking here, I agree that my firstborn child will etc etc...")]
public bool Agreement1Checked { get; set; }

And in the .cshtml file:

@Html.CheckBoxFor(m => m.Agreement1Checked)
@Html.LabelFor(m => m.Agreement1Checked)
@Html.ValidationMessageFor(m => m.Agreement1Checked)

Solution 16 - asp.net Mvc

I think the best way to handle this is just check in your controller if the box is true otherwise just add an error to your model and have it redisplay your view.

As previously stated all [Required] does is make sure there is a value and in your case if not checked you still get false.

Solution 17 - asp.net Mvc

/// <summary> 
///  Summary : -CheckBox for or input type check required validation is not working the root cause and solution as follows
///
///  Problem :
///  The key to this problem lies in interpretation of jQuery validation 'required' rule. I digged a little and find a specific code inside a jquery.validate.unobtrusive.js file:
///  adapters.add("required", function (options) {
///  if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
///    setValidationValues(options, "required", true);
///    }
///   });
///   
///  Fix: (Jquery script fix at page level added in to check box required area)
///  jQuery.validator.unobtrusive.adapters.add("brequired", function (options) {
///   if (options.element.tagName.toUpperCase() == "INPUT" && options.element.type.toUpperCase() == "CHECKBOX") {
///              options.rules["required"] = true;
///   if (options.message) {
///                   options.messages["required"] = options.message;
///                       }
///  Fix : (C# Code for MVC validation)
///  You can see it inherits from common RequiredAttribute. Moreover it implements IClientValidateable. This is to make assure that rule will be propagated to client side (jQuery validation) as well.
///  
///  Annotation example :
///   [BooleanRequired]
///   public bool iAgree { get; set' }
/// </summary>


public class BooleanRequired : RequiredAttribute, IClientValidatable
{

    public BooleanRequired()
    {
    }

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

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        return new ModelClientValidationRule[] { new ModelClientValidationRule() { ValidationType = "brequired", ErrorMessage = this.ErrorMessage } };
    }
}

Solution 18 - asp.net Mvc

Check out Foolproof validation here. You can download/install it via Nuget.

It's a great little library for this kind of thing.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarty TrenouthView Question on Stackoverflow
Solution 1 - asp.net MvcdazbradburyView Answer on Stackoverflow
Solution 2 - asp.net Mvcfields.cageView Answer on Stackoverflow
Solution 3 - asp.net MvcmoribvndvsView Answer on Stackoverflow
Solution 4 - asp.net MvcKapéView Answer on Stackoverflow
Solution 5 - asp.net MvcharvzorView Answer on Stackoverflow
Solution 6 - asp.net Mvcta.speot.isView Answer on Stackoverflow
Solution 7 - asp.net MvcMatthew ManelaView Answer on Stackoverflow
Solution 8 - asp.net MvcSergey KudriavtsevView Answer on Stackoverflow
Solution 9 - asp.net MvclobotommyView Answer on Stackoverflow
Solution 10 - asp.net MvcMattView Answer on Stackoverflow
Solution 11 - asp.net MvcAung San MyintView Answer on Stackoverflow
Solution 12 - asp.net MvcChase FlorellView Answer on Stackoverflow
Solution 13 - asp.net MvcGeorge StockerView Answer on Stackoverflow
Solution 14 - asp.net MvctoddmoView Answer on Stackoverflow
Solution 15 - asp.net MvcDronzView Answer on Stackoverflow
Solution 16 - asp.net MvcsamackView Answer on Stackoverflow
Solution 17 - asp.net Mvcdhandapani harikrishnanView Answer on Stackoverflow
Solution 18 - asp.net MvcDavidWainwrightView Answer on Stackoverflow