私は、次のような検証属性を実装する最善の方法についてアドバイスを求めていました。
モデル
public class MyInputModel
{
[Required]
public int Id {get;set;}
public string MyProperty1 {get;set;}
public string MyProperty2 {get;set;}
public bool MyProperty3 {get;set;}
}
少なくとも prop1、prop2、prop3 に値を持たせたいのですが、prop3 に入力された唯一の値がある場合は false にならないはずです。これに対する検証属性をどのように記述すればよいでしょうか?
ご協力いただきありがとうございます!
ベストアンサー1
昨日も同じ問題がありましたが、クライアント側とサーバー側の両方の検証に機能する非常にクリーンな方法で実行しました。
状態モデル内の他のプロパティの値に基づいて、別のプロパティを必須にします。コードは次のとおりです。
public class RequiredIfAttribute : RequiredAttribute
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
public RequiredIfAttribute(String propertyName, Object desiredvalue)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
Object instance = context.ObjectInstance;
Type type = instance.GetType();
Object proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
if (proprtyvalue.ToString() == DesiredValue.ToString())
{
ValidationResult result = base.IsValid(value, context);
return result;
}
return ValidationResult.Success;
}
}
PropertyName
条件を設定したいプロパティです
DesiredValue
他のプロパティが必須かどうか検証する必要があるPropertyName(プロパティ)の特定の値です。
次のような状況があるとします。
public enum UserType
{
Admin,
Regular
}
public class User
{
public UserType UserType {get;set;}
[RequiredIf("UserType",UserType.Admin,
ErrorMessageResourceName="PasswordRequired",
ErrorMessageResourceType = typeof(ResourceString))]
public string Password { get; set; }
}
最後に、属性のアダプターを登録して、クライアント側での検証ができるようにします (global.asax、Application_Start に配置します)。
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute),
typeof(RequiredAttributeAdapter));
編集済み
クライアント側が何をしても起動しない、または動作しないという問題を報告している人もいます。そこで、上記のコードを修正して、Javascriptでも条件付きクライアント側検証を行うようにしました。この場合、アダプタを登録する必要はありません。
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
private String PropertyName { get; set; }
private Object DesiredValue { get; set; }
private readonly RequiredAttribute _innerAttribute;
public RequiredIfAttribute(String propertyName, Object desiredvalue)
{
PropertyName = propertyName;
DesiredValue = desiredvalue;
_innerAttribute = new RequiredAttribute();
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);
if (dependentValue.ToString() == DesiredValue.ToString())
{
if (!_innerAttribute.IsValid(value))
{
return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = ErrorMessageString,
ValidationType = "requiredif",
};
rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;
yield return rule;
}
}
そして最後に、JavaScript(バンドルしてレンダリングし、独自のスクリプト ファイルに配置します)
$.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options) {
options.rules['requiredif'] = options.params;
options.messages['requiredif'] = options.message;
});
$.validator.addMethod('requiredif', function (value, element, parameters) {
var desiredvalue = parameters.desiredvalue;
desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
var actualvalue = {}
if (controlType == "checkbox" || controlType == "radio") {
var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
actualvalue = control.val();
} else {
actualvalue = $("#" + parameters.dependentproperty).val();
}
if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
var isValid = $.validator.methods.required.call(this, value, element, parameters);
return isValid;
}
return true;
});
明らかに、控えめな検証jQueryを要件として含める必要があります