Как обрабатывать логические / флажки в ASP.NET MVC 2 с помощью DataAnnotations? - PullRequest
46 голосов
/ 11 февраля 2010

У меня есть модель вида, подобная этой:

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 обнуляемым, он не будет работать, потому что компилятор кричит

"Шаблоны могут использоваться только с доступом к полю, доступом к свойству, индексом одномерного массива или выражениями пользовательского индексатора с одним параметром."

Итак, как правильно справиться с этим?

Ответы [ 12 ]

91 голосов
/ 26 апреля 2010

Мое решение выглядит следующим образом (оно не сильно отличается от уже представленных ответов, но я считаю, что оно названо лучше):

/// <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; }
48 голосов
/ 27 января 2012

Я бы создал валидатор как для сервера, так и для клиента. Используя 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, который помещает нашу аннотацию в представление из нашей модели.

18 голосов
/ 11 февраля 2010

Я получил его, создав собственный атрибут:

public class BooleanRequiredAttribute : RequiredAttribute 
{
    public override bool IsValid(object value)
    {
        return value != null && (bool) value;
    }
}
6 голосов
/ 05 марта 2014
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
5 голосов
/ 04 июня 2013

Это может быть "взлом", но вы можете использовать встроенный атрибут Range:

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

Единственная проблема заключается в том, что в строке «предупреждение» будет указано «FIELDNAME должно быть между Истиной и Истиной».

4 голосов
/ 11 февраля 2010

«Обязательно» - неправильная проверка, здесь. Вы хотите что-то похожее на «Должно иметь значение true», которое отличается от «Обязательный». Как насчет использования что-то вроде:

[RegularExpression("^true")]

3 голосов
/ 19 марта 2014

Я просто беру лучшие из существующих решений и объединяю их в единый ответ, который учитывает как проверку на стороне сервера, так и на стороне клиента.

Применяется для моделирования свойств, чтобы гарантировать, что значение bool должно быть истинным:

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

JavaScript, который нужно включить для использования ненавязчивой проверки.

jQuery.validator.addMethod("mustbetrue", function (value, element) {
    return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
3 голосов
/ 06 апреля 2010

Мое решение - это простой пользовательский атрибут для логических значений:

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; }
2 голосов
/ 18 января 2016

Правильный способ сделать это - проверить тип!

[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
2 голосов
/ 28 апреля 2011

Для людей, которые испытывают трудности с получением этой работы для проверки на стороне клиента (ранее я): убедитесь, что у вас также есть

  1. Включено <% Html.EnableClientValidation (); %> перед формой в представлении
  2. Используется <% = Html.ValidationMessage или Html.ValidationMessageFor для поля </li>
  3. Создан DataAnnotationsModelValidator, который возвращает правило с пользовательским типом проверки
  4. Зарегистрированный класс, производный от DataAnnotationsModelValidator, в Global.Application_Start

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

хороший урок по этому, , но пропускает шаг 4.

...