Ответ 1
Я получил его, создав собственный атрибут:
public class BooleanRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool) value;
}
}
У меня есть модель вида:
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 - это тип значения и никогда не имеет значения null. Но даже если я делаю AgreesWithTerms нулевым, это не сработает, потому что компилятор кричит
"Шаблоны могут использоваться только с доступом к полю, доступом к свойствам, индексом одномерного массива или однопараметрическими выражениями пользовательского индексатора."
Итак, каков правильный способ справиться с этим?
Я получил его, создав собственный атрибут:
public class BooleanRequiredAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return value != null && (bool) value;
}
}
Мое решение выглядит следующим образом (он не сильно отличается от уже представленных ответов, но я считаю, что он назван лучше):
/// <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; }
Я бы создал валидатор для обеих сторон сервера и клиента. Используя 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([email protected]"Error Message")]
public bool ThisMustBeTrue{ get; set; }
И наконец, включите проверку на стороне клиента, добавив следующий script к вашему представлению:
<script type="text/javascript">
jQuery.validator.addMethod("enforcetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("enforcetrue");
</script>
Примечание. Мы уже создали метод GetClientValidationRules
, который подталкивает нашу аннотацию к представлению из нашей модели.
[Compare("Remember", ErrorMessage = "You must accept the terms and conditions")]
public bool Remember { get; set; }
Это может быть "взлом", но вы можете использовать встроенный атрибут Range:
[Display(Name = "Accepted Terms Of Service")]
[Range(typeof(bool), "true", "true")]
public bool Terms { get; set; }
Единственная проблема заключается в том, что строка "warning" будет указывать: "FIELDNAME должен быть между True и true".
"Обязательный" - неправильная проверка. Вы хотите нечто похожее на "Должно иметь значение true", что не совпадает с "Обязательным". Как насчет использования чего-то вроде:
[RegularExpression("^true")]
?
Мое решение - это простой пользовательский атрибут для логических значений:
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; }
Я просто использую лучшие из существующих решений и объединяю их в один ответ, который позволяет проверять как на стороне сервера, так и на стороне клиента.
/// <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",
};
}
}
jQuery.validator.addMethod("mustbetrue", function (value, element) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue");
Для людей, которые испытывают трудности с получением этой работы для проверки на стороне клиента (ранее меня): убедитесь, что у вас есть и
- хороший учебник по этому поводу, , но пропускает шаг 4.
Правильный способ сделать это - проверить тип!
[Range(typeof(bool), "true", "true", ErrorMessage = "You must or else!")]
public bool AgreesWithTerms { get; set; }
Здесь найдено более полное решение (проверка как на стороне сервера, так и на стороне клиента):
http://blog.degree.no/2012/03/validation-of-required-checkbox-in-asp-net-mvc/#comments
Достаточно добавить [RegularExpression]:
[DisplayName("I accept terms and conditions")]
[RegularExpression("True", ErrorMessage = "You must accept the terms and conditions")]
public bool AgreesWithTerms { get; set; }
Примечание. "Истина" должна начинаться с капитала T