web-dev-qa-db-ja.com

検証のためのデータ注釈、少なくとも1つの必須フィールド?

フィールドのリストを含む検索オブジェクトがある場合、System.ComponentModel.DataAnnotations名前空間を使用して、検索のフィールドの少なくとも1つがnullまたは空でないことを検証するように設定できますか?つまり、すべてのフィールドはオプションですが、少なくとも1つは常に入力する必要があります。

32
Boob

このためのカスタムバリデーターを作成します。クライアント側の検証は提供されず、サーバー側のみが提供されます。

これが機能するには、値型がデフォルトで0またはnullableになるため、false型を使用する必要があることに注意してください。

まず、新しいバリデーターを作成します。

using System.ComponentModel.DataAnnotations;
using System.Reflection;

// This is a class-level attribute, doesn't make sense at the property level
[AttributeUsage(AttributeTargets.Class)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
  // Have to override IsValid
  public override bool IsValid(object value)
  {
    //  Need to use reflection to get properties of "value"...
    var typeInfo = value.GetType();

    var propertyInfo = typeInfo.GetProperties();

    foreach (var property in propertyInfo)
    {
      if (null != property.GetValue(value, null))
      {
        // We've found a property with a value
        return true;
      }
    }

    // All properties were null.
    return false;
  }
}

次に、これでモデルを装飾できます。

[AtLeastOneProperty(ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}

次に、ModelState.IsValidを呼び出すと、バリデーターが呼び出され、メッセージがビューのValidationSummaryに追加されます。

これを拡張して、戻ってくるプロパティのタイプを確認するか、必要に応じて検証に含める/検証から除外する属性を探すことができます-これは、検証しているタイプについて何も知らない汎用バリデーターを想定しています。

23

プロパティのグループ化をサポートするためにZhaphの回答を拡張しました。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
    private string[] PropertyList { get; set; }

    public AtLeastOnePropertyAttribute(params string[] propertyList)
    {
        this.PropertyList = propertyList;
    }

    //See http://stackoverflow.com/a/1365669
    public override object TypeId
    {
        get
        {
            return this;
        }
    }

    public override bool IsValid(object value)
    {
        PropertyInfo propertyInfo;
        foreach (string propertyName in PropertyList)
        {
            propertyInfo = value.GetType().GetProperty(propertyName);

            if (propertyInfo != null && propertyInfo.GetValue(value, null) != null)
            {
                return true;
            }
        }

        return false;
    }
}

使用法:

[AtLeastOneProperty("StringProp", "Id", "BoolProp", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}

また、2つ(またはそれ以上)のグループが必要な場合:

[AtLeastOneProperty("StringProp", "Id", ErrorMessage="You must supply at least one value")]
[AtLeastOneProperty("BoolProp", "BoolPropNew", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
    public bool? BoolPropNew { get; set; }
}
25
Valerio Gentile

この質問はかなり古いものですが、.NET 3.5(私は信じています)の時点で、 IValidatableObject はトリッキーな検証状況に役立ちます。これを実装して、任意のビジネスルールを検証できます。この場合、次のようになります。

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (string.IsNullOrWhiteSpace(FieldOne) && string.IsNullOrWhiteSpace(FieldTwo))
        yield return new ValidationResult("Must provide value for either FieldOne or FieldTwo.", new string[] { "FieldOne", "FieldTwo" });
}
1
fordareh

アノテーションを付けずに.Netクラスに対して複雑な検証を行う場合は、 FluentValidation を参照するか、.Net 2.0の場合は FluentValidation for 2. を参照してください。

0
Daniel Dyson