ASP.NET MVC:DataAnnotationによるカスタム検証


110

文字列型の4つのプロパティを持つモデルがあります。StringLengthアノテーションを使用して、単一のプロパティの長さを検証できることを知っています。ただし、4つのプロパティを組み合わせた長さを検証したいと思います。

データアノテーションでこれを行うMVCの方法は何ですか?

私はMVCが初めてで、自分のソリューションを作成する前に正しい方法でそれを実行したいので、これを求めています。


2
Fluent Validationを見たことがありますか?データ注釈よりもはるかに優れた複雑なシナリオを処理します
levelnis 2013

強く推奨されるソリューションを見てください。... dotnetcurry.com/ShowArticle.aspx?ID=776
Niks

回答ありがとうございます。私はFluent Validationをチェックしますが、聞いたことはありません。そして、ニックス、ダーリンは基本的にあなたが投稿したリンクの記事が何を説明したかを書きました。だから、ありがとう...素晴らしいもの!
Danny van der Kraan 2013

回答:


177

カスタム検証属性を書くことができます:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}

そして、あなたはビューモデルを持っていて、それでそのプロパティの1つを装飾するかもしれません:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}

4
回答いただきありがとうございます。実際に少し恥ずかしい感じがします。ソリューション全体を書きました。へへ。IsValid関数を変更するだけで、最大長を確認できます。それで、これはこれらのタイプの問題の受け入れられたMVCソリューションですか?
Danny van der Kraan 2013

7
@DannyvanderKraan、はい、これは受け入れられた方法です。もちろん、これはひどくひどいので、私はそれを決して使用せず、検証を実行する代わりにFluentValidation.NETを使用します。
Darin Dimitrov

11
ここ:fluentvalidation.codeplex.com。次のように見える可能性のあるビューモデルの単純なバリデーター(コードは1行)を作成したとしますthis.RuleFor(x => x.Foo).Must((x, foo) => x.Foo.Length + x.Bar.Length + x.Baz.Length < 20).WithMessage("The combined minimum length of the Foo, Bar and Baz properties should be longer than 20");。次に、データアノテーションを使用して記述する必要があるという私の回答のコードを見て、どちらを使用するかを教えてください。宣言的検証モデルは、命令型モデルと比較して非常に貧弱です。
Darin Dimitrov

1
これは少し遅いですが、カスタムデータアノテーションを許可するために「オンにする」必要がある別の設定があるかどうか誰かが知っていますか?web.configファイルに邪魔にならないjsの名前空間を追加することは知っていますが、それ以外の場所はありますか?
ホセ

1
私が探していたこのすべての朝!私はそれを強化しましたが、残念ながらIsValidが呼び出されたときはvalidationContextis nullです。私が間違ったことを何か考えていますか?:-(
Grimm The Opiner 2013年

95

自己検証モデル

モデルはインターフェースを実装する必要がありますIValidatableObject。検証コードをValidateメソッドに入れます:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}

注意してください:これはサーバー側の検証です。クライアント側では機能しません。検証はフォームの送信後にのみ実行されます。


アンドレイに答えてくれてありがとう。あなたの解決策もうまくいくでしょうが、私はそれがより再利用可能であるのでダーリンのものを選びます。
Danny van der Kraan 2013

6
yield return new ValidationResult( "title is required。"、 "Title"); プロパティ名を追加します。これは、必要に応じて検証エラーをグループ化して表示するのに役立ちます。
マイクキングスコット2013

5
この検証メソッドは、すべての検証属性が検証に合格した後にのみ呼び出されることに注意してください。
ペドロ

3
私の検証は非常に具体的だったので、これは私にはうまくいきました。検証が再利用されないので、カスタム属性を追加することは私にとってやり過ぎでした。
Steve S

これは私が探しているものです。ありがとうございました!
Amol Jadhav

27

ExpressiveAnnotationsはそのような可能性を提供します。

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }

これは素晴らしいです!私の祈りは答えられました:)
Korayem

この答えを見つけただけで、時間の節約になります。ExpressiveAnnotationsは素晴らしいです!
ブラッド

10

ダリンの答えを改善するには、少し短くすることができます:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}

モデル:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]

エラーメッセージが必要であることに注意してください。そうでない場合、エラーは空になります。


8

バックグラウンド:

モデルの検証は、受信した受信データが有効かつ正しいことを確認し、このデータを使用してさらに処理できるようにするために必要です。アクションメソッドでモデルを検証できます。組み込みの検証属性は、Compare、Range、RegularExpression、Required、StringLengthです。ただし、組み込み以外の検証属性が必要なシナリオがある場合があります。

カスタム検証属性

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}

カスタム検証属性を作成するには、このクラスをValidationAttributeから派生させる必要があります。

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}

お役に立てれば。乾杯!

参考文献


1

答えに少し遅れますが、誰が検索しているのか。データアノテーションで追加のプロパティを使用することにより、これを簡単に行うことができます。

public string foo { get; set; }
public string bar { get; set; }

[MinLength(20, ErrorMessage = "too short")]
public string foobar 
{ 
    get
    {
        return foo + bar;
    }
}

それだけです。検証エラーも特定の場所に表示したい場合は、ビューにこれを追加できます。

@Html.ValidationMessage("foobar", "your combined text is too short")

ローカリゼーションを行う場合は、ビューでこれを行うと便利です。

お役に立てれば!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.