ASP.NET MVC: Validasi Kustom oleh DataAnnotation


110

Saya memiliki Model dengan 4 properti yang bertipe string. Saya tahu Anda dapat memvalidasi panjang satu properti dengan menggunakan anotasi StringLength. Namun saya ingin memvalidasi panjang dari 4 properti yang digabungkan.

Apa cara MVC untuk melakukan ini dengan anotasi data?

Saya menanyakan ini karena saya baru mengenal MVC dan ingin melakukannya dengan cara yang benar sebelum membuat solusi sendiri.


2
Sudahkah Anda melihat Validasi Lancar? Ini menangani skenario kompleks jauh lebih baik daripada Anotasi Data
levelnis

Lihatlah solusi yang sangat direkomendasikan .... dotnetcurry.com/ShowArticle.aspx?ID=776
Niks

Terimakasih telah menjawab. Saya akan memeriksa Validasi Lancar, belum pernah mendengarnya. Dan Niks, Darin pada dasarnya menulis apa yang dijelaskan artikel di tautan yang Anda posting. Jadi, terima kasih ... Hal yang luar biasa!
Danny van der Kraan

Jawaban:


177

Anda dapat menulis atribut validasi khusus:

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;
    }
}

lalu Anda mungkin memiliki model tampilan dan menghias salah satu propertinya dengannya:

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
Terima kasih telah menjawab, saya menerima jawaban Anda. Merasa agak malu sebenarnya. Anda menulis seluruh solusi! Hehe. Hanya perlu mengubah fungsi IsValid untuk memeriksa panjang maksimal. Jadi, apakah ini solusi MVC yang diterima untuk jenis masalah ini?
Danny van der Kraan

7
@DannyvanderKraan, ya, ini adalah cara yang diterima. Tentu saja ini sangat menyebalkan sehingga saya tidak pernah menggunakannya dan menggunakan FluentValidation.NET sebagai gantinya untuk melakukan validasi.
Darin Dimitrov

11
Di sini: fluentvalidation.codeplex.com . Anda bisa saja menulis sebuah validator sederhana untuk tampilan model yang mungkin tampak seperti ini (satu baris kode): 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");. Sekarang lihat kode dalam jawaban saya yang perlu Anda tulis dengan anotasi data dan beri tahu saya mana yang Anda sukai. Model validasi deklaratif sangat buruk dibandingkan dengan model imperatif.
Darin Dimitrov

1
Ini agak terlambat, tetapi apakah ada yang tahu jika ada setelan berbeda yang harus Anda "aktifkan" untuk mengizinkan anotasi data ubahsuaian? Saya tahu tentang menambahkan namespace untuk js yang tidak mengganggu di file web.config, tetapi di tempat lain?
Jose

1
Saya sudah mencari ini sepanjang pagi! Saya telah mengimplementasikannya, dan sayangnya ketika IsValiddipanggil validationContextadalah null. Tahu apa yang saya lakukan salah? :-(
Grimm The Opiner

95

Model yang divalidasi sendiri

Model Anda harus mengimplementasikan sebuah antarmuka IValidatableObject. Masukkan kode validasi Anda ke dalam Validatemetode:

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) });
    }
}

Harap perhatikan: ini adalah validasi sisi server . Itu tidak bekerja di sisi klien. Validasi Anda akan dilakukan hanya setelah pengiriman formulir.


Terima kasih telah menjawab Andrei. Sementara solusi Anda juga akan berhasil, saya memilih Darin's karena lebih dapat digunakan kembali.
Danny van der Kraan

6
menghasilkan pengembalian baru ValidationResult ("Judul wajib diisi.", "Judul"); akan menambahkan nama properti, berguna dalam mengelompokkan kesalahan validasi untuk ditampilkan jika perlu.
Mike Kingscott

5
Perhatikan bahwa metode validasi ini hanya dipanggil setelah semua atribut validasi lulus validasi.
Pedro

3
Ini bekerja dengan baik untuk saya karena validasi saya sangat spesifik. Menambahkan atribut khusus akan berlebihan bagi saya karena validasi tidak akan digunakan kembali.
Steve S

Inilah yang saya cari. Terima kasih!
Amol Jadhav

27

ExpressiveAnnotations memberi Anda kemungkinan seperti itu:

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

Ini luar biasa! doa saya dijawab :)
Korayem

Baru saja menemukan jawaban ini dan ini hanya menghemat banyak waktu. ExpressiveAnnotations sangat brilian!
Brad

10

Untuk memperbaiki jawaban Darwin, ini bisa sedikit lebih singkat:

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);
    }
}

Model:

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

Perhatikan bahwa pesan kesalahan diperlukan, jika tidak kesalahan akan kosong.


8

Latar Belakang:

Validasi model diperlukan untuk memastikan bahwa data yang diterima yang kami terima valid dan benar sehingga kami dapat melakukan pemrosesan lebih lanjut dengan data ini. Kami dapat memvalidasi model dalam metode tindakan. Atribut validasi bawaan adalah Compare, Range, RegularExpression, Required, StringLength. Namun kami mungkin memiliki skenario di mana kami memerlukan atribut validasi selain yang sudah ada di dalamnya.

Atribut Validasi Kustom

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;}
}

Untuk membuat atribut validasi khusus, Anda harus mendapatkan kelas ini dari 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;
    }
}

Semoga ini membantu. Bersulang !

Referensi


1

Agak terlambat untuk menjawab, tapi untuk siapa yang mencari. Anda dapat dengan mudah melakukan ini dengan menggunakan properti tambahan dengan anotasi data:

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

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

Itu semua terlalu itu. Jika Anda benar-benar ingin menampilkan kesalahan validasi di tempat tertentu juga, Anda dapat menambahkan ini dalam tampilan Anda:

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

melakukan ini dalam tampilan bisa berguna jika Anda ingin melakukan pelokalan.

Semoga ini membantu!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.