Модель MVC вимагає true


85

Чи є спосіб за допомогою анотацій даних вимагати, щоб для логічного властивості було встановлено значення true?

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

Який саме варіант використання цього? Не могли б ви просто дозволити властивості лише для читання і постійно повертати істину?
— Jan Thomä

1
Це майже те, що можна сказати ... привіт, приятелю, ти забув перевірити Я погоджуюсь ... що повинно зробити модель недійсною.
— Марті Тренут,

Я думаю, це те, що ви хотіли б обробляти на стороні клієнта.
— PsychoCoder

15
@PsychoCoder: Це слід обробляти з обох сторін ... не лише з боку клієнта. Я просто шукав, чи можна з цим впоратися, додавши просту анотацію даних.
— Марті Тренут,

Відповіді:


49

Ви можете створити власний валідатор:

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
}

Я хотів би покращити це за допомогою реалізації на стороні клієнта - замість використання віддаленої перевірки, про яку йдеться в інших відповідях, скористайтеся ненав’язливим викладеним тут: jacopretorius.net/2011/01/client-side-validation-in-mvc-3 .html
— SamStephens

Це хороше (і перевірене) швидке рішення для нас. Ми можемо обійтися без перевірки на стороні клієнта в рішенні @ dazbradbury (також хорошому), оскільки нам це потрібно лише в одиночному прапорці на минулій сторінці опитування.
— Сет

return (bool) value == true;це надмірне порівняння
— T-moty

130

Я б створив валідатор як для сервера, так і для клієнта. Використовуючи 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 який висуває нашу анотацію до подання з нашої моделі.

Якщо ви використовуєте файли ресурсів для надсилання повідомлення про помилку для інтернаціоналізації, видаліть FormatErrorMessageвиклик (або просто зателефонуйте до бази) і налаштуйте GetClientValidationRulesметод так:

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

3
Дякую за це - це чудово працює! Це працює краще із видаленим методом перевизначення FormatErrorMessage - таким чином працює локалізація повідомлень про помилки з файлів ресурсів. Моє використання: [EnforceTrue (ErrorMessageResourceType = typeof (ValidationMessages), ErrorMessageResourceName = "TermsAndConditionsRequired")]
— Метт Фрір,

2
Я не можу змусити перевірку на стороні клієнта працювати і, здається, не можу сказати, що я роблю неправильно. Куди саме слід покласти javacsript? У тегу head? Поруч з контролером?
— vsdev

Я згоден, це має бути відповідь
— Сімуа

1
Чудове рішення, що демонструє потужність спеціальних атрибутів перевірки! Хоча я рекомендую помістити сценарій у js-файл із глобальним посиланням, а не у представлення (види) для повторного використання. Крім того, найкраще обробляти всі способи додавання рядків повідомлень: за замовчуванням, якщо не передбачено, або рядок повідомлення, або з файлу ресурсу.
— jeepwran

1
Чудове рішення, дякую за публікацію. Для тих, хто не може змусити роботу клієнтської перевірки: Вам потрібно розширити перевірку jQuery до того, як елементи керування, які вона перевірятиме, будуть завантажені, тому помістіть скрипт в заголовок, а не у window.onload / $ (документ ) .ready () подія.
— Еверт

92

Я знаю, що це старіший пост, але я хотів поділитися простим способом на стороні сервера. Ви створюєте загальнодоступну властивість, встановлену на true, і порівнюєте свій bool із цією властивістю. Якщо ваш bool не позначений (за замовчуванням false), форма не перевірятиметься.

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

Код бритви

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

12
+1 для простоти. FYI: Мені довелося опублікувати власність isTrue, щоб це працювало.
— Тод Бірдсолл,

Порівняння не існує для мене в MVC4
— Майкл Руднер Еванчик

Супер рішення відмінне рішення
— Sreerejith SS

9
І якщо ви додасте прихований для властивості "isTrue", ви отримаєте перевірку на стороні клієнта
— billoreid

2
Дратувати це чудове рішення не працювало для мене. Перевірено на Mvc 5.2.3.
— harvzor

22

Я спробував кілька рішень, але жодне з них не працювало повністю для мене, щоб отримати перевірку як на стороні клієнта, так і на сервері. Отже, що я зробив у своєму додатку MVC 5, щоб змусити його працювати:

У вашому ViewModel (для перевірки на стороні сервера):

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

На вашій сторінці Razor (для перевірки на стороні клієнта):

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

1
Чарівне рішення!
— Тобіас,

3
Подбайте про значення для прихованого поля ("true")!
— Тобіас,

10

Я просто хотів би направити людей до такої скрипки: https://dotnetfiddle.net/JbPh0X

Користувач додав [Range(typeof(bool), "true", "true", ErrorMessage = "You gotta tick the box!")]до свого логічного властивості, що змушує перевірку на стороні сервера працювати.

Для того, щоб перевірка на стороні клієнта також працювала, вони додали такий сценарій:

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

9

Просто перевірте, чи дорівнює його рядкове представлення True:

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

@JeradRose Це просто перевірено на сервері. Ви маєте на увазі перевірку на стороні клієнта?
— ta.speot.is

3
Підтверджено, це працює на стороні сервера, але не на стороні клієнта
— Метт Фрір,

Я думав, що перевірка на стороні сервера може мати виняток невідповідності типу, намагаючись порівняти bool із рядком.
— Jerad Rose

RegularExpressionAttributeвнутрішньо використовує Convert.ToStringдля отримання рядкового представлення значення властивості (яке доставляється йому як object).
— ta.speot.is

Я думаю, що ця відповідь простіша, ніж @ fields-cage +1 від мене
— Аарон Гудон,

5

Ви можете створити власний атрибут або скористатися CustomValidationAttribute .

Ось як ви використовуєте CustomValidationAttribute:

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

де BoolValidation визначається як:

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

5

[Required]атрибут означає будь-яке значення - воно може бути як true, так і false. Для цього вам доведеться використовувати іншу перевірку.


3

Продовження допису ta.speot.is та коментаря Джерада Роуза:

Дана публікація не працюватиме на стороні клієнта з ненав’язливою валідацією. Це має працювати в обох таборах (клієнт і сервер):

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

Не знаю, чи це проблема новішої версії, але вона не працює для мене з jquery.validate 1.19.2 та jquery.validate.unobtrusive 3.2.11. Проблема, схоже, полягає в тому, що regexметод ненав’язливий визначає спочатку перевіряє, чи є цей прапорець необов’язковим, перед тим, як перевірити регулярний вираз, що має сенс, за винятком того, що jquery.validate, здається, розглядає будь-який невстановлений прапорець необов’язковим. tl; dr Він запускає регулярний вираз лише на позначених прапорцях. Ми можемо додати прокладку для regex validatorметоду або просто створити власний валідатор.
— xr280xr

3

.NET Core MVC - Обов’язковий прапорець із анотаціями даних

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>

Дайте кредит: jasonwatmore.com/post/2013/10/16/…
— xr280xr

2

Я не знаю способу проходження DataAnnotations, але це легко зробити у вашому контролері.

public ActionResult Add(Domain.Something model)
{

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

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

}

Єдиним іншим варіантом буде створення власного валідатора на стороні сервера та віддаленого валідатора на стороні клієнта (віддалена перевірка доступна лише в MVC3 +)


Начебто вже нове, як уже перевірити логічний прапор .... хотілося знати, чи є для нього анотація даних.
— Marty Trenouth

2

Чи є у вас відповідні елементи, налаштовані в web.config ?

Це може спричинити непрацювання перевірки.

Ви також можете спробувати створити власний атрибут перевірки (оскільки [Required]лише важливо, чи існує він, і ви дбаєте про значення):

[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);
    }
}

Потім використання:

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

Від сюди .


2

Це те, що мені вдалося. Більше нічого не було. Mvc 5:

Модель

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

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

Переглянути

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

введіть тут опис зображення

введіть тут опис зображення


2

Для ASP.NET Core MVC є перевірка клієнта та сервера на основі рішення dazbradbury

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

А потім на клієнта:

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

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

Тоді використання:

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

1

Я спробував використати відповідь fields.cage, і це мені не вдалося, але щось простіше, і я не впевнений, чому саме (інша версія Razor, можливо?), Але все, що мені потрібно було зробити, це:

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

А у файлі .cshtml:

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

Для мене це не працює на стороні клієнта. З якоїсь причини параметр, переданий методу правила jquery.validate, є [NaN, NaN]там, де він повинен бути[true, true]
— xr280xr

@ xr280xr Навіть коли користувач встановив прапорець?
— Дронц

0

Я думаю, що найкращий спосіб вирішити це - просто перевірити у своєму контролері, чи вірно інакше, інакше просто додайте помилку до вашої моделі та повторно відображте ваш погляд.

Як було зазначено раніше, все [Обов’язково] - це переконатися, що є значення, і у вашому випадку, якщо не встановлено прапорець, ви все одно отримуєте false.


0

Ознайомтеся з неперевершеним підтвердженням тут . Ви можете завантажити / встановити його через Nuget.

Це чудова маленька бібліотека для такого роду речей.


Е-е-е ... Атрибути перевірки за замовчуванням працюють досить добре.
— Пангамма,

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

Хоча це посилання може відповісти на питання, краще включити сюди основні частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
— Раві Дорія,

Він працює Перевірити це посилання причини , чому вона не на validation- itmeze.com/2010/12/06 / ...
— dhandapani Харікрішнан

Сьогодні це працює. Чи можете ви бути впевнені, що він продовжить працювати через 5, 10 років потому? Ці БД запитань та відповідей створені також для майбутніх користувачів
— Еліяху,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.