次のようなビューモデルがあります。
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(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
を既に作成しました。
[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; }
唯一の問題は、「警告」文字列が「FIELDNAMEはTrueとtrueの間でなければならない」と言うことです。
ここで「必須」は間違った検証です。 「必須」とは異なる「値をtrueにする必要がある」に似たものが必要です。次のようなものを使用するのはどうですか:
[RegularExpression("^true")]
?
既存のソリューションを最大限に活用して、サーバー側とクライアント側の両方の検証を可能にする単一の回答にまとめています。
/// <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");
私の解決策は、ブール値用のこの単純なカスタム属性です。
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; }
クライアント側で検証のためにこれを機能させるのに苦労している人(以前は私):あなたも持っていることを確認してください
これを行うための良いチュートリアルですが、手順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; }
注-「True」は大文字のTで始まる必要があります