Модель 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.