web-dev-qa-db-ja.com

リストのViewModel検証

私は次のビューモデル定義を持っています

public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

したがって、私のアプリケーションでは、アクセス要求に対して少なくとも1人が必要です。検証にどのアプローチを使用できますか?コントローラーでこの検証を行うのは望ましくありませんが、これは簡単です。唯一の選択肢はカスタム検証属性ですか?

編集:現在FluentValidationでこの検証を実行しています(素敵なライブラリ!)

RuleFor(vm => vm.Persons)
                .Must((vm, person) => person.Count > 0)
                .WithMessage("At least one person is required");
71
ryan

データ注釈を使用して検証を実行している場合、カスタム属性が必要になる場合があります。

public class EnsureOneElementAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count > 0;
        }
        return false;
    }
}

その後:

[EnsureOneElement(ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

または、より汎用的にするには:

public class EnsureMinimumElementsAttribute : ValidationAttribute
{
    private readonly int _minElements;
    public EnsureMinimumElementsAttribute(int minElements)
    {
        _minElements = minElements;
    }

    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count >= _minElements;
        }
        return false;
    }
}

その後:

[EnsureMinimumElements(1, ErrorMessage = "At least a person is required")]
public List<Person> Persons { get; private set; }

個人的には、宣言の代わりに命令型の検証ロジックを好むため、検証を実行するためにデータ注釈の代わりに FluentValidation.NET を使用します。もっと強力だと思います。したがって、検証ルールは次のようになります。

RuleFor(x => x.Persons)
    .Must(x => x.Count > 0)
    .WithMessage("At least a person is required");
155
Darin Dimitrov

ビューモデルオブジェクトのコレクションメンバーのカウント検証を処理する別の可能な方法は、コレクションまたはリストカウントを返す計算プロパティを持つことです。その後、以下のコードのようにRangeAttributeを適用して、カウント検証を実施できます。

[Range(minimum: 1, maximum: Int32.MaxValue, ErrorMessage = "At least one item needs to be selected")]
public int ItemCount
{
    get
    {
        return Items != null ? Items.Length : 0;
    }
}

上記のコードでは、ItemCountは検証されているビューモデルの計算プロパティの例であり、Itemsはカウントが確認されているメンバーコレクションプロパティの例です。この例では、少なくとも1つの項目がコレクションメンバーに適用され、最大制限は整数がとることができる最大値です。これは、実際の目的のほとんどで無制限です。検証失敗時のエラーメッセージは、上記の例のRangeAttributeのErrorMessageメンバーを通じて設定することもできます。

13
Sudhir

ダリンの答えは良いですが、以下のバージョンは自動的に有用なエラーメッセージを提供します。

public class MinimumElementsAttribute : ValidationAttribute
{
    private readonly int minElements;

    public MinimumElementsAttribute(int minElements)
    {
        this.minElements = minElements;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var list = value as IList;

        var result = list?.Count >= minElements;

        return result
            ? ValidationResult.Success
            : new ValidationResult($"{validationContext.DisplayName} requires at least {minElements} element" + (minElements > 1 ? "s" : string.Empty));
    }
}

使用法:

[MinimumElements(1)]
public List<Customer> Customers {get;set}

[MinimumElements(2)]
public List<Address> Addresses {get;set}

エラーメッセージ:

  • 顧客には少なくとも1つの要素が必要です
  • 住所には少なくとも2つの要素が必要です
5
Sam Shiles

次のコードは、asp.netコア1.1で機能します。

[Required, MinLength(1, ErrorMessage = "At least one item required in work order")]
public ICollection<WorkOrderItem> Items { get; set; }
4
rahulmohan

ここには2つの選択肢があります。カスタム検証属性を作成してプロパティを装飾するか、ViewModelにIValidatableObjectインターフェイス(Validateメソッドを定義する)を実装させることができます

お役に立てれば :)

1
AbdouMoumen

1つの方法は、プライベートコンストラクターと静的メソッドを使用してオブジェクトのインスタンスを返すことです。

public class AccessRequestViewModel
{
    private AccessRequesetViewModel() { };

    public static GetAccessRequestViewModel (List<Person> persons)
    {
            return new AccessRequestViewModel()
            {
                Persons = persons,
            };
    }

    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    public List<Person> Persons { get; private set; }
}

常にファクトリを使用してViewModelをインスタンス化することにより、常に人がいることを保証できます。

これはおそらくあなたが望むものには理想的ではありませんが、おそらくうまくいくでしょう。

0
Ian P

カスタム検証を行うと、非常にクリーンでエレガントになります。このようなもの:

_public class AccessRequestViewModel
{
    public Request Request { get; private set; }
    public SelectList Buildings { get; private set; }
    [AtLeastOneItem]
    public List<Person> Persons { get; private set; }
}
_

または[MinimumItems(1)]

0
goenning