Validasi model di ASP.NET Core MVC dan Razor Pages

Artikel ini menjelaskan cara memvalidasi input pengguna di aplikasi ASP.NET Core MVC atau Razor Pages.

Lihat atau unduh sampel kode (cara mengunduh).

Status model

Status model mewakili kesalahan yang berasal dari dua subsistem: pengikatan model dan validasi model. Kesalahan yang berasal dari pengikatan model umumnya adalah kesalahan konversi data. Misalnya, "x" dimasukkan dalam bidang bilangan bulat. Validasi model terjadi setelah pengikatan model dan melaporkan kesalahan di mana data tidak sesuai dengan aturan bisnis. Misalnya, 0 dimasukkan dalam bidang yang mengharapkan peringkat antara 1 dan 5.

Pengikatan model dan validasi model terjadi sebelum eksekusi tindakan pengontrol atau Razor metode handler Pages. Untuk aplikasi web, aplikasi bertanggung jawab untuk memeriksa ModelState.IsValid dan bereaksi dengan tepat. Aplikasi web biasanya memutar ulang halaman dengan pesan kesalahan, seperti yang diperlihatkan dalam contoh Halaman berikut Razor :

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Untuk ASP.NET Core MVC dengan pengontrol dan tampilan, contoh berikut menunjukkan cara memeriksa ModelState.IsValid di dalam tindakan pengontrol:

public async Task<IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }

    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
}

Pengontrol API Web tidak perlu memeriksa apakah ModelState.IsValid mereka memiliki atribut [ApiController ]. Dalam hal ini, respons HTTP 400 otomatis yang berisi detail kesalahan dikembalikan ketika status model tidak valid. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

Menjalankan ulang validasi

Validasi otomatis, tetapi Anda mungkin ingin mengulanginya secara manual. Misalnya, Anda mungkin menghitung nilai untuk properti dan ingin menjalankan ulang validasi setelah mengatur properti ke nilai komputasi. Untuk menjalankan kembali validasi, panggil ModelStateDictionary.ClearValidationState untuk menghapus validasi khusus untuk model yang sedang divalidasi diikuti oleh TryValidateModel:

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Atribut validasi

Atribut validasi memungkinkan Anda menentukan aturan validasi untuk properti model. Contoh berikut dari aplikasi sampel menunjukkan kelas model yang diannotasikan dengan atribut validasi. Atribut [ClassicMovie] adalah atribut validasi kustom dan yang lain dibangun. Tidak ditampilkan adalah [ClassicMovieWithClientValidator], yang menunjukkan cara alternatif untuk mengimplementasikan atribut kustom.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Atribut bawaan

Berikut adalah beberapa atribut validasi bawaan:

  • [ValidateNever]: Menunjukkan bahwa properti atau parameter harus dikecualikan dari validasi.
  • [CreditCard]: Memvalidasi bahwa properti memiliki format kartu kredit. Memerlukan Metode Tambahan Validasi jQuery.
  • [Bandingkan]: Memvalidasi bahwa dua properti dalam kecocokan model.
  • [EmailAddress]: Memvalidasi bahwa properti memiliki format email.
  • [Telepon]: Memvalidasi bahwa properti memiliki format nomor telepon.
  • [Rentang]: Memvalidasi bahwa nilai properti berada dalam rentang tertentu.
  • [RegularExpression]: Memvalidasi bahwa nilai properti cocok dengan ekspresi reguler tertentu.
  • [Wajib]: Memvalidasi bahwa bidang tidak null. Lihat [Required] atribut untuk detail tentang perilaku atribut ini.
  • [StringLength]: Memvalidasi bahwa nilai properti string tidak melebihi batas panjang yang ditentukan.
  • [Url]: Memvalidasi bahwa properti memiliki format URL.
  • [Remote]: Memvalidasi input pada klien dengan memanggil metode tindakan di server. Lihat [Remote] atribut untuk detail tentang perilaku atribut ini.

Daftar lengkap atribut validasi dapat ditemukan di System.ComponentModel.DataAnnotations namespace layanan.

Pesan kesalahan

Atribut validasi memungkinkan Anda menentukan pesan kesalahan yang akan ditampilkan untuk input yang tidak valid. Contohnya:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Secara internal, atribut memanggil String.Format dengan tempat penampung untuk nama bidang dan terkadang tempat penampung tambahan. Contohnya:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Saat diterapkan ke properti, pesan kesalahan yang Name dibuat oleh kode sebelumnya adalah "Panjang nama harus antara 6 dan 8.".

Untuk mengetahui parameter mana yang diteruskan untuk String.Format pesan kesalahan atribut tertentu, lihat kode sumber DataAnnotations.

Gunakan JSnama properti ON dalam kesalahan validasi

Secara default, ketika kesalahan validasi terjadi, validasi model menghasilkan ModelStateDictionary dengan nama properti sebagai kunci kesalahan. Beberapa aplikasi, seperti aplikasi halaman tunggal, mendapat manfaat menggunakan JSnama properti ON untuk kesalahan validasi yang dihasilkan dari API Web. Kode berikut mengonfigurasi validasi untuk menggunakan SystemTextJsonValidationMetadataProvider nama properti ON JS:

using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider());
});

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Kode berikut mengonfigurasi validasi untuk menggunakan NewtonsoftJsonValidationMetadataProvider nama properti ON JSsaat menggunakan Json.NET:

using Microsoft.AspNetCore.Mvc.NewtonsoftJson;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers(options =>
{
    options.ModelMetadataDetailsProviders.Add(new NewtonsoftJsonValidationMetadataProvider());
}).AddNewtonsoftJson();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Untuk contoh kebijakan untuk menggunakan camel-casing, lihat Program.cs di GitHub.

Jenis referensi yang tidak dapat diubah ke null dan atribut [Wajib]

Sistem validasi memperlakukan parameter yang tidak dapat diubah ke null atau properti terikat seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Dengan mengaktifkan Nullable konteks, MVC secara implisit mulai memvalidasi properti atau parameter yang tidak dapat diubah ke null seolah-olah telah dikaitkan dengan [Required(AllowEmptyStrings = true)] atribut . Pertimbangkan gambar berikut:

public class Person
{
    public string Name { get; set; }
}

Jika aplikasi dibuat dengan <Nullable>enable</Nullable>, nilai yang hilang untuk Name di JSON atau posting formulir menghasilkan kesalahan validasi. Ini mungkin tampak kontradiktif karena [Required(AllowEmptyStrings = true)] atribut tersirat, tetapi ini adalah perilaku yang diharapkan karena string kosong dikonversi ke null secara default. Gunakan tipe referensi nullable untuk memperbolehkan nilai null atau hilang ditentukan untuk Name properti:

public class Person
{
    public string? Name { get; set; }
}

Perilaku ini dapat dinonaktifkan dengan mengonfigurasi SuppressImplicitRequiredAttributeForNonNullableReferenceTypes di Program.cs:

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Validasi [wajib] pada server

Pada server, nilai yang diperlukan dianggap hilang jika properti null. Bidang yang tidak dapat diubah ke null selalu valid, dan [Required] pesan kesalahan atribut tidak pernah ditampilkan.

Namun, pengikatan model untuk properti yang tidak dapat diubah ke null mungkin gagal, mengakibatkan pesan kesalahan seperti The value '' is invalid. Untuk menentukan pesan kesalahan kustom untuk validasi sisi server dari jenis yang tidak dapat diubah ke null, Anda memiliki opsi berikut:

  • Buat bidang nullable (misalnya, decimal? bukan decimal). Jenis nilai T> nullable<diperlakukan seperti jenis nullable standar.

  • Tentukan pesan kesalahan default yang akan digunakan oleh pengikatan model, seperti yang ditunjukkan dalam contoh berikut:

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

    Untuk informasi selengkapnya tentang kesalahan pengikatan model yang dapat Anda atur pesan defaultnya, lihat DefaultModelBindingMessageProvider.

Validasi [Wajib] pada klien

Jenis dan string yang tidak dapat diubah ke null ditangani secara berbeda pada klien dibandingkan dengan server. Di klien:

  • Nilai dianggap hanya ada jika input dimasukkan untuknya. Oleh karena itu, validasi sisi klien menangani jenis yang tidak dapat diubah ke null sama dengan jenis nullable.
  • Spasi kosong dalam bidang string dianggap sebagai input yang valid oleh metode yang diperlukan Validasi jQuery. Validasi sisi server menganggap bidang string yang diperlukan tidak valid jika hanya spasi kosong yang dimasukkan.

Seperti disebutkan sebelumnya, jenis yang tidak dapat diubah ke null diperlakukan seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Itu berarti Anda mendapatkan validasi sisi klien meskipun Anda tidak menerapkan [Required(AllowEmptyStrings = true)] atribut . Tetapi jika Anda tidak menggunakan atribut , Anda mendapatkan pesan kesalahan default. Untuk menentukan pesan kesalahan kustom, gunakan atribut .

Atribut [Remote]

Atribut [Remote] mengimplementasikan validasi sisi klien yang mengharuskan memanggil metode di server untuk menentukan apakah input bidang valid. Misalnya, aplikasi mungkin perlu memverifikasi apakah nama pengguna sudah digunakan.

Untuk menerapkan validasi jarak jauh:

  1. Buat metode tindakan untuk dipanggil JavaScript. Metode jarak jauh Validasi jQuery mengharapkan JSrespons ON:

    • true berarti data input valid.
    • false, undefined, atau null berarti input tidak valid. Tampilkan pesan kesalahan default.
    • String lainnya berarti input tidak valid. Tampilkan string sebagai pesan kesalahan kustom.

    Berikut adalah contoh metode tindakan yang mengembalikan pesan kesalahan kustom:

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Di kelas model, anotasi properti dengan [Remote] atribut yang menunjuk ke metode tindakan validasi, seperti yang ditunjukkan dalam contoh berikut:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; } = null!;
    

Validasi sisi server juga perlu diterapkan untuk klien yang telah menonaktifkan JavaScript.

Bidang tambahan

Properti AdditionalFields[Remote] atribut memungkinkan Anda memvalidasi kombinasi bidang terhadap data di server. Misalnya, jika User model memiliki FirstName properti dan LastName , Anda mungkin ingin memverifikasi bahwa tidak ada pengguna yang sudah memiliki sepasang nama tersebut. Contoh berikut menunjukkan cara menggunakan AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;

AdditionalFields dapat diatur secara eksplisit ke string "FirstName" dan "LastName", tetapi menggunakan operator nameof menyederhanakan pemfaktoran ulang nanti. Metode tindakan untuk validasi ini harus menerima argumen firstName dan lastName :

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

Saat pengguna memasukkan nama depan atau belakang, JavaScript melakukan panggilan jarak jauh untuk melihat apakah pasangan nama tersebut telah diambil.

Untuk memvalidasi dua atau beberapa bidang tambahan, berikan sebagai daftar yang dibatasi koma. Misalnya, untuk menambahkan MiddleName properti ke model, atur [Remote] atribut seperti yang ditunjukkan dalam contoh berikut:

[Remote(action: "VerifyName", controller: "Users",
    AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, seperti semua argumen atribut, harus berupa ekspresi konstan. Oleh karena itu, jangan gunakan string atau panggilan Join terinterpolasi untuk menginisialisasi AdditionalFields .

Alternatif untuk atribut bawaan

Jika Anda memerlukan validasi yang tidak disediakan oleh atribut bawaan, Anda dapat:

Mengelola atribut kustom

Untuk skenario yang tidak ditangani atribut validasi bawaan, Anda dapat membuat atribut validasi kustom. Buat kelas yang mewarisi dari ValidationAttribute, dan ambil alih IsValid metode .

Metode IsValid menerima objek bernama value, yang merupakan input yang akan divalidasi. Kelebihan beban juga menerima ValidationContext objek, yang menyediakan informasi tambahan, seperti instans model yang dibuat oleh pengikatan model.

Contoh berikut memvalidasi bahwa tanggal rilis untuk film dalam genre Klasik tidak lebih dari tahun yang ditentukan. Atribut [ClassicMovie] :

  • Hanya dijalankan di server.
  • Untuk film Klasik, memvalidasi tanggal rilis:
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

Variabel movie dalam contoh sebelumnya mewakili Movie objek yang berisi data dari pengiriman formulir. Saat validasi gagal, dengan ValidationResult pesan kesalahan dikembalikan.

IValidatableObject

Contoh sebelumnya hanya berfungsi dengan Movie jenis. Opsi lain untuk validasi tingkat kelas adalah menerapkan IValidatableObject di kelas model, seperti yang ditunjukkan dalam contoh berikut:

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

Validasi kustom

Kode berikut menunjukkan cara menambahkan kesalahan model setelah memeriksa model:

if (Contact.Name == Contact.ShortName)
{
    ModelState.AddModelError("Contact.ShortName", 
                             "Short name can't be the same as Name.");
}

Kode berikut mengimplementasikan pengujian validasi dalam pengontrol:

if (contact.Name == contact.ShortName)
{
    ModelState.AddModelError(nameof(contact.ShortName),
                             "Short name can't be the same as Name.");
}

Kode berikut memverifikasi nomor telepon dan email unik:

public async Task<IActionResult> OnPostAsync()
{
    // Attach Validation Error Message to the Model on validation failure.          

    if (Contact.Name == Contact.ShortName)
    {
        ModelState.AddModelError("Contact.ShortName", 
                                 "Short name can't be the same as Name.");
    }

    if (_context.Contact.Any(i => i.PhoneNumber == Contact.PhoneNumber))
    {
        ModelState.AddModelError("Contact.PhoneNumber",
                                  "The Phone number is already in use.");
    }
    if (_context.Contact.Any(i => i.Email == Contact.Email))
    {
        ModelState.AddModelError("Contact.Email", "The Email is already in use.");
    }

    if (!ModelState.IsValid || _context.Contact == null || Contact == null)
    {
        // if model is invalid, return the page with the model state errors.
        return Page();
    }
    _context.Contact.Add(Contact);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Kode berikut mengimplementasikan pengujian validasi dalam pengontrol:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,ShortName,Email,PhoneNumber")] Contact contact)
{
    // Attach Validation Error Message to the Model on validation failure.
    if (contact.Name == contact.ShortName)
    {
        ModelState.AddModelError(nameof(contact.ShortName),
                                 "Short name can't be the same as Name.");
    }

    if (_context.Contact.Any(i => i.PhoneNumber == contact.PhoneNumber))
    {
        ModelState.AddModelError(nameof(contact.PhoneNumber),
                                  "The Phone number is already in use.");
    }
    if (_context.Contact.Any(i => i.Email == contact.Email))
    {
        ModelState.AddModelError(nameof(contact.Email), "The Email is already in use.");
    }

    if (ModelState.IsValid)
    {
        _context.Add(contact);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(contact);
}

Memeriksa nomor telepon atau email unik biasanya juga dilakukan dengan validasi jarak jauh.

ValidationResult

Pertimbangkan kustom ValidateNameAttributeberikut:

public class ValidateNameAttribute : ValidationAttribute
{
    public ValidateNameAttribute()
    {
        const string defaultErrorMessage = "Error with Name";
        ErrorMessage ??= defaultErrorMessage;
    }

    protected override ValidationResult? IsValid(object? value,
                                         ValidationContext validationContext)
    {
        if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
        {
            return new ValidationResult("Name is required.");
        }

        if (value.ToString()!.ToLower().Contains("zz"))
        {

            return new ValidationResult(
                        FormatErrorMessage(validationContext.DisplayName));
        }

        return ValidationResult.Success;
    }
}

Dalam kode berikut, atribut kustom [ValidateName] diterapkan:

public class Contact
{
    public Guid Id { get; set; }

    [ValidateName(ErrorMessage = "Name must not contain `zz`")] 
    public string? Name { get; set; }
    public string? Email { get; set; }
    public string? PhoneNumber { get; set; }
}

Saat model berisi zz, baru ValidationResult dikembalikan.

Validasi simpul tingkat atas

Simpul tingkat atas meliputi:

  • Parameter Tindakan
  • Properti pengontrol
  • Parameter handler halaman
  • Properti model halaman

Simpul tingkat atas yang terikat model divalidasi selain memvalidasi properti model. Dalam contoh berikut dari aplikasi sampel, VerifyPhone metode menggunakan RegularExpressionAttribute untuk memvalidasi phone parameter tindakan:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Simpul tingkat atas dapat digunakan BindRequiredAttribute dengan atribut validasi. Dalam contoh berikut dari aplikasi sampel, CheckAge metode menentukan bahwa age parameter harus terikat dari string kueri saat formulir dikirimkan:

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Di halaman Periksa Usia (CheckAge.cshtml), ada dua formulir. Formulir pertama mengirimkan Age nilai 99 sebagai parameter string kueri: https://localhost:5001/Users/CheckAge?Age=99.

Saat parameter yang diformat age dengan benar dari string kueri dikirimkan, formulir memvalidasi.

Formulir kedua pada halaman Periksa Usia mengirimkan Age nilai dalam isi permintaan, dan validasi gagal. Pengikatan gagal karena age parameter harus berasal dari string kueri.

Kesalahan maksimum

Validasi berhenti ketika jumlah maksimum kesalahan tercapai (200 secara default). Anda dapat mengonfigurasi nomor ini dengan kode berikut di Program.cs:

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

builder.Services.AddSingleton
    <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

Rekursi maksimum

ValidationVisitor melintasi grafik objek model yang sedang divalidasi. Untuk model yang dalam atau rekursif tanpa batas, validasi dapat mengakibatkan luapan tumpukan. MvcOptions.MaxValidationDepth menyediakan cara untuk menghentikan validasi lebih awal jika rekursi pengunjung melebihi kedalaman yang dikonfigurasi. Nilai default adalah MvcOptions.MaxValidationDepth 32.

Sirkuit pendek otomatis

Validasi secara otomatis memiliki sirkuit pendek (dilewati) jika grafik model tidak memerlukan validasi. Objek yang dilewati runtime validasi untuk menyertakan koleksi primitif (seperti byte[], , string[]Dictionary<string, string>) dan grafik objek kompleks yang tidak memiliki validator apa pun.

Validasi sisi klien

Validasi sisi klien mencegah pengiriman hingga formulir valid. Tombol Kirim menjalankan JavaScript yang mengirimkan formulir atau menampilkan pesan kesalahan.

Validasi sisi klien menghindari perjalanan pulang pergi yang tidak perlu ke server ketika ada kesalahan input pada formulir. Referensi skrip berikut dalam _Layout.cshtml dan _ValidationScriptsPartial.cshtml mendukung validasi sisi klien:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>

Skrip Validasi jQuery Unobtrusive adalah pustaka front-end Microsoft kustom yang dibangun pada plugin Validasi jQuery populer. Tanpa Validasi jQuery Unobtrusive, Anda harus mengodekan logika validasi yang sama di dua tempat: sekali di atribut validasi sisi server pada properti model, dan kemudian lagi dalam skrip sisi klien. Sebagai gantinya, Pembantu Tag dan pembantu HTML menggunakan atribut validasi dan mengetik metadata dari properti model untuk merender atribut HTML 5 data- untuk elemen formulir yang memerlukan validasi. jQuery Unobtrusive Validation mengurai data- atribut dan meneruskan logika ke Validasi jQuery, secara efektif "menyalin" logika validasi sisi server ke klien. Anda dapat menampilkan kesalahan validasi pada klien menggunakan pembantu tag seperti yang ditunjukkan di sini:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

Pembantu tag sebelumnya merender HTML berikut:

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

Perhatikan bahwa data- atribut dalam output HTML sesuai dengan atribut validasi untuk Movie.ReleaseDate properti . Atribut data-val-required berisi pesan kesalahan untuk ditampilkan jika pengguna tidak mengisi bidang tanggal rilis. jQuery Unobtrusive Validation meneruskan nilai ini ke metode jQuery Validation required(), yang kemudian menampilkan pesan tersebut dalam elemen rentang> yang <menyertainya.

Validasi jenis data didasarkan pada jenis .NET properti, kecuali jika ditimpa oleh atribut [DataType ]. Browser memiliki pesan kesalahan default mereka sendiri, tetapi paket Validasi jQuery Validation Tidak Mengganggu dapat mengambil alih pesan tersebut. [DataType] atribut dan subkelas seperti [EmailAddress] memungkinkan Anda menentukan pesan kesalahan.

Validasi tidak mengganggu

Untuk informasi tentang validasi yang tidak mengganggu, lihat masalah GitHub ini.

Menambahkan Validasi ke Formulir Dinamis

jQuery Unobtrusive Validation meneruskan logika validasi dan parameter ke Validasi jQuery saat halaman pertama kali dimuat. Oleh karena itu, validasi tidak berfungsi secara otomatis pada formulir yang dihasilkan secara dinamis. Untuk mengaktifkan validasi, beri tahu jQuery Unobtrusive Validation untuk mengurai formulir dinamis segera setelah Anda membuatnya. Misalnya, kode berikut menyiapkan validasi sisi klien pada formulir yang ditambahkan melalui AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

Metode $.validator.unobtrusive.parse() menerima pemilih jQuery untuk satu argumennya. Metode ini memberi tahu jQuery Unobtrusive Validation untuk mengurai atribut formulir dalam pemilih tersebut data- . Nilai atribut tersebut kemudian diteruskan ke plugin Validasi jQuery.

Menambahkan Validasi ke Kontrol Dinamis

Metode ini $.validator.unobtrusive.parse() bekerja pada seluruh formulir, bukan pada kontrol yang dihasilkan secara dinamis individu, seperti <input> dan <select/>. Untuk memilah ulang formulir, hapus data validasi yang ditambahkan saat formulir diurai sebelumnya, seperti yang ditunjukkan dalam contoh berikut:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Validasi sisi klien kustom

Validasi sisi klien kustom dilakukan dengan menghasilkan data- atribut HTML yang berfungsi dengan adaptor Validasi jQuery kustom. Contoh kode adaptor berikut ditulis untuk [ClassicMovie] atribut dan [ClassicMovieWithClientValidator] yang diperkenalkan sebelumnya dalam artikel ini:

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

Untuk informasi tentang cara menulis adaptor, lihat dokumentasi Validasi jQuery.

Penggunaan adaptor untuk bidang tertentu dipicu oleh data- atribut yang:

  • Benderai bidang sebagai tunduk pada validasi (data-val="true").
  • Identifikasi nama aturan validasi dan teks pesan kesalahan (misalnya, data-val-rulename="Error message.").
  • Berikan parameter tambahan apa pun yang dibutuhkan validator (misalnya, data-val-rulename-param1="value").

Contoh berikut menunjukkan data- atribut untuk atribut aplikasiClassicMovie sampel:

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

Seperti disebutkan sebelumnya, Pembantu Tag dan pembantu HTML menggunakan informasi dari atribut validasi untuk merender data- atribut. Ada dua opsi untuk menulis kode yang menghasilkan pembuatan atribut HTML kustom data- :

  • Buat kelas yang berasal dari AttributeAdapterBase<TAttribute> dan kelas yang mengimplementasikan IValidationAttributeAdapterProvider, dan daftarkan atribut Anda dan adaptornya di DI. Metode ini mengikuti prinsip tanggung jawab tunggal dalam kode validasi terkait server dan terkait klien berada di kelas terpisah. Adaptor juga memiliki keuntungan bahwa karena terdaftar di DI, layanan lain di DI tersedia untuk itu jika diperlukan.
  • Terapkan IClientModelValidator di kelas Anda ValidationAttribute . Metode ini mungkin sesuai jika atribut tidak melakukan validasi sisi server apa pun dan tidak memerlukan layanan apa pun dari DI.

AttributeAdapter untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovie atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  1. Buat kelas adaptor atribut untuk atribut validasi kustom. Dapatkan kelas dari AttributeAdapterBase<TAttribute>. Buat metode yang menambahkan data- atribut ke output yang dirender, seperti yang AddValidation ditunjukkan dalam contoh ini:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(
            ClassicMovieAttribute attribute, IStringLocalizer? stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
            => Attribute.GetErrorMessage();
    }
    
  2. Buat kelas penyedia adaptor yang mengimplementasikan IValidationAttributeAdapterProvider. Dalam metode berikan atribut kustom ke konstruktor adaptor, seperti yang GetAttributeAdapter ditunjukkan dalam contoh ini:

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter? GetAttributeAdapter(
            ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. Daftarkan penyedia adaptor untuk DI di Program.cs:

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovieWithClientValidator atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  • Dalam atribut validasi kustom, terapkan IClientModelValidator antarmuka dan buat AddValidation metode . Dalam metode , AddValidation tambahkan data- atribut untuk validasi, seperti yang ditunjukkan dalam contoh berikut:

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
            => Year = year;
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult? IsValid(
            object? value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value!).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

Menonaktifkan validasi sisi klien

Kode berikut menonaktifkan validasi klien di Razor Pages:

builder.Services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

Opsi lain untuk menonaktifkan validasi sisi klien:

  • Komentari referensi ke _ValidationScriptsPartial dalam semua .cshtml file.
  • Hapus konten file Pages\Shared_ValidationScriptsPartial.cshtml .

Pendekatan sebelumnya tidak akan mencegah validasi sisi klien ASP.NET IdentityRazor Core Class Library. Untuk informasi selengkapnya, lihat Perancah Identity dalam proyek ASP.NET Core.

Detail masalah

Detail Masalah bukan satu-satunya format respons untuk menjelaskan kesalahan API HTTP, namun, biasanya digunakan untuk melaporkan kesalahan untuk API HTTP.

Layanan detail masalah mengimplementasikan IProblemDetailsService antarmuka, yang mendukung pembuatan detail masalah di ASP.NET Core. Metode AddProblemDetails ekstensi pada IServiceCollection mendaftarkan implementasi default IProblemDetailsService .

Di aplikasi ASP.NET Core, middleware berikut menghasilkan respons HTTP detail masalah saat AddProblemDetails dipanggil, kecuali ketika Accept header HTTP permintaan tidak menyertakan salah satu jenis konten yang didukung oleh yang terdaftar IProblemDetailsWriter (default: application/json):

Sumber Daya Tambahan:

Artikel ini menjelaskan cara memvalidasi input pengguna di aplikasi ASP.NET Core MVC atau Razor Pages.

Lihat atau unduh sampel kode (cara mengunduh).

Status model

Status model mewakili kesalahan yang berasal dari dua subsistem: pengikatan model dan validasi model. Kesalahan yang berasal dari pengikatan model umumnya adalah kesalahan konversi data. Misalnya, "x" dimasukkan dalam bidang bilangan bulat. Validasi model terjadi setelah pengikatan model dan melaporkan kesalahan di mana data tidak sesuai dengan aturan bisnis. Misalnya, 0 dimasukkan dalam bidang yang mengharapkan peringkat antara 1 dan 5.

Pengikatan model dan validasi model terjadi sebelum eksekusi tindakan pengontrol atau Razor metode handler Pages. Untuk aplikasi web, aplikasi bertanggung jawab untuk memeriksa ModelState.IsValid dan bereaksi dengan tepat. Aplikasi web biasanya memutar ulang halaman dengan pesan kesalahan, seperti yang diperlihatkan dalam contoh Halaman berikut Razor :

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Untuk ASP.NET Core MVC dengan pengontrol dan tampilan, contoh berikut menunjukkan cara memeriksa ModelState.IsValid di dalam tindakan pengontrol:

public async Task<IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }

    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
}

Pengontrol API Web tidak perlu memeriksa apakah ModelState.IsValid mereka memiliki atribut [ApiController ]. Dalam hal ini, respons HTTP 400 otomatis yang berisi detail kesalahan dikembalikan ketika status model tidak valid. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

Menjalankan ulang validasi

Validasi otomatis, tetapi Anda mungkin ingin mengulanginya secara manual. Misalnya, Anda mungkin menghitung nilai untuk properti dan ingin menjalankan ulang validasi setelah mengatur properti ke nilai komputasi. Untuk menjalankan kembali validasi, panggil ModelStateDictionary.ClearValidationState untuk menghapus validasi khusus untuk model yang sedang divalidasi diikuti oleh TryValidateModel:

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Atribut validasi

Atribut validasi memungkinkan Anda menentukan aturan validasi untuk properti model. Contoh berikut dari aplikasi sampel menunjukkan kelas model yang diannotasikan dengan atribut validasi. Atribut [ClassicMovie] adalah atribut validasi kustom dan yang lain dibangun. Tidak ditampilkan adalah [ClassicMovieWithClientValidator], yang menunjukkan cara alternatif untuk mengimplementasikan atribut kustom.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Atribut bawaan

Berikut adalah beberapa atribut validasi bawaan:

  • [ValidateNever]: Menunjukkan bahwa properti atau parameter harus dikecualikan dari validasi.
  • [CreditCard]: Memvalidasi bahwa properti memiliki format kartu kredit. Memerlukan Metode Tambahan Validasi jQuery.
  • [Bandingkan]: Memvalidasi bahwa dua properti dalam kecocokan model.
  • [EmailAddress]: Memvalidasi bahwa properti memiliki format email.
  • [Telepon]: Memvalidasi bahwa properti memiliki format nomor telepon.
  • [Rentang]: Memvalidasi bahwa nilai properti berada dalam rentang tertentu.
  • [RegularExpression]: Memvalidasi bahwa nilai properti cocok dengan ekspresi reguler tertentu.
  • [Wajib]: Memvalidasi bahwa bidang tidak null. Lihat [Required] atribut untuk detail tentang perilaku atribut ini.
  • [StringLength]: Memvalidasi bahwa nilai properti string tidak melebihi batas panjang yang ditentukan.
  • [Url]: Memvalidasi bahwa properti memiliki format URL.
  • [Remote]: Memvalidasi input pada klien dengan memanggil metode tindakan di server. Lihat [Remote] atribut untuk detail tentang perilaku atribut ini.

Daftar lengkap atribut validasi dapat ditemukan di System.ComponentModel.DataAnnotations namespace layanan.

Pesan kesalahan

Atribut validasi memungkinkan Anda menentukan pesan kesalahan yang akan ditampilkan untuk input yang tidak valid. Contohnya:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Secara internal, atribut memanggil String.Format dengan tempat penampung untuk nama bidang dan terkadang tempat penampung tambahan. Contohnya:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Saat diterapkan ke properti, pesan kesalahan yang Name dibuat oleh kode sebelumnya adalah "Panjang nama harus antara 6 dan 8.".

Untuk mengetahui parameter mana yang diteruskan untuk String.Format pesan kesalahan atribut tertentu, lihat kode sumber DataAnnotations.

Jenis referensi yang tidak dapat diubah ke null dan atribut [Wajib]

Sistem validasi memperlakukan parameter yang tidak dapat diubah ke null atau properti terikat seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Dengan mengaktifkan Nullable konteks, MVC secara implisit mulai memvalidasi properti yang tidak dapat diubah ke null pada jenis atau parameter non-generik seolah-olah telah dikaitkan dengan [Required(AllowEmptyStrings = true)] atribut . Pertimbangkan gambar berikut:

public class Person
{
    public string Name { get; set; }
}

Jika aplikasi dibuat dengan <Nullable>enable</Nullable>, nilai yang hilang untuk Name di JSON atau posting formulir menghasilkan kesalahan validasi. Gunakan tipe referensi nullable untuk memperbolehkan nilai null atau hilang ditentukan untuk Name properti:

public class Person
{
    public string? Name { get; set; }
}

Perilaku ini dapat dinonaktifkan dengan mengonfigurasi SuppressImplicitRequiredAttributeForNonNullableReferenceTypes di Program.cs:

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Properti yang tidak dapat diubah ke null pada jenis generik dan atribut [Wajib]

Properti yang tidak dapat diubah ke null pada jenis generik harus menyertakan [Required] atribut saat jenis diperlukan. Dalam kode berikut, TestRequired tidak diperlukan:

public class WeatherForecast<T>
{
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

Dalam kode berikut, TestRequired secara eksplisit ditandai sebagaimana diperlukan:

using System.ComponentModel.DataAnnotations;

public class WeatherForecast<T>
{
    [Required]
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

Validasi [wajib] pada server

Pada server, nilai yang diperlukan dianggap hilang jika properti null. Bidang yang tidak dapat diubah ke null selalu valid, dan [Required] pesan kesalahan atribut tidak pernah ditampilkan.

Namun, pengikatan model untuk properti yang tidak dapat diubah ke null mungkin gagal, mengakibatkan pesan kesalahan seperti The value '' is invalid. Untuk menentukan pesan kesalahan kustom untuk validasi sisi server dari jenis yang tidak dapat diubah ke null, Anda memiliki opsi berikut:

  • Buat bidang nullable (misalnya, decimal? bukan decimal). Jenis nilai T> nullable<diperlakukan seperti jenis nullable standar.

  • Tentukan pesan kesalahan default yang akan digunakan oleh pengikatan model, seperti yang ditunjukkan dalam contoh berikut:

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

    Untuk informasi selengkapnya tentang kesalahan pengikatan model yang dapat Anda atur pesan defaultnya, lihat DefaultModelBindingMessageProvider.

Validasi [Wajib] pada klien

Jenis dan string yang tidak dapat diubah ke null ditangani secara berbeda pada klien dibandingkan dengan server. Di klien:

  • Nilai dianggap hanya ada jika input dimasukkan untuknya. Oleh karena itu, validasi sisi klien menangani jenis yang tidak dapat diubah ke null sama dengan jenis nullable.
  • Spasi kosong dalam bidang string dianggap sebagai input yang valid oleh metode yang diperlukan Validasi jQuery. Validasi sisi server menganggap bidang string yang diperlukan tidak valid jika hanya spasi kosong yang dimasukkan.

Seperti disebutkan sebelumnya, jenis yang tidak dapat diubah ke null diperlakukan seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Itu berarti Anda mendapatkan validasi sisi klien meskipun Anda tidak menerapkan [Required(AllowEmptyStrings = true)] atribut . Tetapi jika Anda tidak menggunakan atribut , Anda mendapatkan pesan kesalahan default. Untuk menentukan pesan kesalahan kustom, gunakan atribut .

Atribut [Remote]

Atribut [Remote] mengimplementasikan validasi sisi klien yang mengharuskan memanggil metode di server untuk menentukan apakah input bidang valid. Misalnya, aplikasi mungkin perlu memverifikasi apakah nama pengguna sudah digunakan.

Untuk menerapkan validasi jarak jauh:

  1. Buat metode tindakan untuk dipanggil JavaScript. Metode jarak jauh Validasi jQuery mengharapkan JSrespons ON:

    • true berarti data input valid.
    • false, undefined, atau null berarti input tidak valid. Tampilkan pesan kesalahan default.
    • String lainnya berarti input tidak valid. Tampilkan string sebagai pesan kesalahan kustom.

    Berikut adalah contoh metode tindakan yang mengembalikan pesan kesalahan kustom:

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Di kelas model, anotasi properti dengan [Remote] atribut yang menunjuk ke metode tindakan validasi, seperti yang ditunjukkan dalam contoh berikut:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; } = null!;
    

Bidang tambahan

Properti AdditionalFields[Remote] atribut memungkinkan Anda memvalidasi kombinasi bidang terhadap data di server. Misalnya, jika User model memiliki FirstName properti dan LastName , Anda mungkin ingin memverifikasi bahwa tidak ada pengguna yang sudah memiliki sepasang nama tersebut. Contoh berikut menunjukkan cara menggunakan AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;

AdditionalFields dapat diatur secara eksplisit ke string "FirstName" dan "LastName", tetapi menggunakan operator nameof menyederhanakan pemfaktoran ulang nanti. Metode tindakan untuk validasi ini harus menerima argumen firstName dan lastName :

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

Saat pengguna memasukkan nama depan atau belakang, JavaScript melakukan panggilan jarak jauh untuk melihat apakah pasangan nama tersebut telah diambil.

Untuk memvalidasi dua atau beberapa bidang tambahan, berikan sebagai daftar yang dibatasi koma. Misalnya, untuk menambahkan MiddleName properti ke model, atur [Remote] atribut seperti yang ditunjukkan dalam contoh berikut:

[Remote(action: "VerifyName", controller: "Users",
    AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, seperti semua argumen atribut, harus berupa ekspresi konstan. Oleh karena itu, jangan gunakan string atau panggilan Join terinterpolasi untuk menginisialisasi AdditionalFields .

Alternatif untuk atribut bawaan

Jika Anda memerlukan validasi yang tidak disediakan oleh atribut bawaan, Anda dapat:

Mengelola atribut kustom

Untuk skenario yang tidak ditangani atribut validasi bawaan, Anda dapat membuat atribut validasi kustom. Buat kelas yang mewarisi dari ValidationAttribute, dan ambil alih IsValid metode .

Metode IsValid menerima objek bernama value, yang merupakan input yang akan divalidasi. Kelebihan beban juga menerima ValidationContext objek, yang menyediakan informasi tambahan, seperti instans model yang dibuat oleh pengikatan model.

Contoh berikut memvalidasi bahwa tanggal rilis untuk film dalam genre Klasik tidak lebih dari tahun yang ditentukan. Atribut [ClassicMovie] :

  • Hanya dijalankan di server.
  • Untuk film Klasik, memvalidasi tanggal rilis:
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

Variabel movie dalam contoh sebelumnya mewakili Movie objek yang berisi data dari pengiriman formulir. Saat validasi gagal, dengan ValidationResult pesan kesalahan dikembalikan.

IValidatableObject

Contoh sebelumnya hanya berfungsi dengan Movie jenis. Opsi lain untuk validasi tingkat kelas adalah menerapkan IValidatableObject di kelas model, seperti yang ditunjukkan dalam contoh berikut:

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

Validasi simpul tingkat atas

Simpul tingkat atas meliputi:

  • Parameter Tindakan
  • Properti pengontrol
  • Parameter handler halaman
  • Properti model halaman

Simpul tingkat atas yang terikat model divalidasi selain memvalidasi properti model. Dalam contoh berikut dari aplikasi sampel, VerifyPhone metode menggunakan RegularExpressionAttribute untuk memvalidasi phone parameter tindakan:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Simpul tingkat atas dapat digunakan BindRequiredAttribute dengan atribut validasi. Dalam contoh berikut dari aplikasi sampel, CheckAge metode menentukan bahwa age parameter harus terikat dari string kueri saat formulir dikirimkan:

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Di halaman Periksa Usia (CheckAge.cshtml), ada dua formulir. Formulir pertama mengirimkan Age nilai 99 sebagai parameter string kueri: https://localhost:5001/Users/CheckAge?Age=99.

Saat parameter yang diformat age dengan benar dari string kueri dikirimkan, formulir memvalidasi.

Formulir kedua pada halaman Periksa Usia mengirimkan Age nilai dalam isi permintaan, dan validasi gagal. Pengikatan gagal karena age parameter harus berasal dari string kueri.

Kesalahan maksimum

Validasi berhenti ketika jumlah maksimum kesalahan tercapai (200 secara default). Anda dapat mengonfigurasi nomor ini dengan kode berikut di Program.cs:

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

builder.Services.AddSingleton
    <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

Rekursi maksimum

ValidationVisitor melintasi grafik objek model yang sedang divalidasi. Untuk model yang dalam atau rekursif tanpa batas, validasi dapat mengakibatkan luapan tumpukan. MvcOptions.MaxValidationDepth menyediakan cara untuk menghentikan validasi lebih awal jika rekursi pengunjung melebihi kedalaman yang dikonfigurasi. Nilai default adalah MvcOptions.MaxValidationDepth 32.

Sirkuit pendek otomatis

Validasi secara otomatis memiliki sirkuit pendek (dilewati) jika grafik model tidak memerlukan validasi. Objek yang dilewati runtime validasi untuk menyertakan koleksi primitif (seperti byte[], , string[]Dictionary<string, string>) dan grafik objek kompleks yang tidak memiliki validator apa pun.

Validasi sisi klien

Validasi sisi klien mencegah pengiriman hingga formulir valid. Tombol Kirim menjalankan JavaScript yang mengirimkan formulir atau menampilkan pesan kesalahan.

Validasi sisi klien menghindari perjalanan pulang pergi yang tidak perlu ke server ketika ada kesalahan input pada formulir. Referensi skrip berikut dalam _Layout.cshtml dan _ValidationScriptsPartial.cshtml mendukung validasi sisi klien:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>

Skrip Validasi jQuery Unobtrusive adalah pustaka front-end Microsoft kustom yang dibangun pada plugin Validasi jQuery populer. Tanpa Validasi jQuery Unobtrusive, Anda harus mengodekan logika validasi yang sama di dua tempat: sekali di atribut validasi sisi server pada properti model, dan kemudian lagi dalam skrip sisi klien. Sebagai gantinya, Pembantu Tag dan pembantu HTML menggunakan atribut validasi dan mengetik metadata dari properti model untuk merender atribut HTML 5 data- untuk elemen formulir yang memerlukan validasi. jQuery Unobtrusive Validation mengurai data- atribut dan meneruskan logika ke Validasi jQuery, secara efektif "menyalin" logika validasi sisi server ke klien. Anda dapat menampilkan kesalahan validasi pada klien menggunakan pembantu tag seperti yang ditunjukkan di sini:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

Pembantu tag sebelumnya merender HTML berikut:

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

Perhatikan bahwa data- atribut dalam output HTML sesuai dengan atribut validasi untuk Movie.ReleaseDate properti . Atribut data-val-required berisi pesan kesalahan untuk ditampilkan jika pengguna tidak mengisi bidang tanggal rilis. jQuery Unobtrusive Validation meneruskan nilai ini ke metode jQuery Validation required(), yang kemudian menampilkan pesan tersebut dalam elemen rentang> yang <menyertainya.

Validasi jenis data didasarkan pada jenis .NET properti, kecuali jika ditimpa oleh atribut [DataType ]. Browser memiliki pesan kesalahan default mereka sendiri, tetapi paket Validasi jQuery Validation Tidak Mengganggu dapat mengambil alih pesan tersebut. [DataType] atribut dan subkelas seperti [EmailAddress] memungkinkan Anda menentukan pesan kesalahan.

Validasi tidak mengganggu

Untuk informasi tentang validasi yang tidak mengganggu, lihat masalah GitHub ini.

Menambahkan Validasi ke Formulir Dinamis

jQuery Unobtrusive Validation meneruskan logika validasi dan parameter ke Validasi jQuery saat halaman pertama kali dimuat. Oleh karena itu, validasi tidak berfungsi secara otomatis pada formulir yang dihasilkan secara dinamis. Untuk mengaktifkan validasi, beri tahu jQuery Unobtrusive Validation untuk mengurai formulir dinamis segera setelah Anda membuatnya. Misalnya, kode berikut menyiapkan validasi sisi klien pada formulir yang ditambahkan melalui AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

Metode $.validator.unobtrusive.parse() menerima pemilih jQuery untuk satu argumennya. Metode ini memberi tahu jQuery Unobtrusive Validation untuk mengurai atribut formulir dalam pemilih tersebut data- . Nilai atribut tersebut kemudian diteruskan ke plugin Validasi jQuery.

Menambahkan Validasi ke Kontrol Dinamis

Metode ini $.validator.unobtrusive.parse() bekerja pada seluruh formulir, bukan pada kontrol yang dihasilkan secara dinamis individu, seperti <input> dan <select/>. Untuk memilah ulang formulir, hapus data validasi yang ditambahkan saat formulir diurai sebelumnya, seperti yang ditunjukkan dalam contoh berikut:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Validasi sisi klien kustom

Validasi sisi klien kustom dilakukan dengan menghasilkan data- atribut HTML yang berfungsi dengan adaptor Validasi jQuery kustom. Contoh kode adaptor berikut ditulis untuk [ClassicMovie] atribut dan [ClassicMovieWithClientValidator] yang diperkenalkan sebelumnya dalam artikel ini:

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

Untuk informasi tentang cara menulis adaptor, lihat dokumentasi Validasi jQuery.

Penggunaan adaptor untuk bidang tertentu dipicu oleh data- atribut yang:

  • Benderai bidang sebagai tunduk pada validasi (data-val="true").
  • Identifikasi nama aturan validasi dan teks pesan kesalahan (misalnya, data-val-rulename="Error message.").
  • Berikan parameter tambahan apa pun yang dibutuhkan validator (misalnya, data-val-rulename-param1="value").

Contoh berikut menunjukkan data- atribut untuk atribut aplikasiClassicMovie sampel:

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

Seperti disebutkan sebelumnya, Pembantu Tag dan pembantu HTML menggunakan informasi dari atribut validasi untuk merender data- atribut. Ada dua opsi untuk menulis kode yang menghasilkan pembuatan atribut HTML kustom data- :

  • Buat kelas yang berasal dari AttributeAdapterBase<TAttribute> dan kelas yang mengimplementasikan IValidationAttributeAdapterProvider, dan daftarkan atribut Anda dan adaptornya di DI. Metode ini mengikuti prinsip tanggung jawab tunggal dalam kode validasi terkait server dan terkait klien berada di kelas terpisah. Adaptor juga memiliki keuntungan bahwa karena terdaftar di DI, layanan lain di DI tersedia untuk itu jika diperlukan.
  • Terapkan IClientModelValidator di kelas Anda ValidationAttribute . Metode ini mungkin sesuai jika atribut tidak melakukan validasi sisi server apa pun dan tidak memerlukan layanan apa pun dari DI.

AttributeAdapter untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovie atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  1. Buat kelas adaptor atribut untuk atribut validasi kustom. Dapatkan kelas dari AttributeAdapterBase<TAttribute>. Buat metode yang menambahkan data- atribut ke output yang dirender, seperti yang AddValidation ditunjukkan dalam contoh ini:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(
            ClassicMovieAttribute attribute, IStringLocalizer? stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
            => Attribute.GetErrorMessage();
    }
    
  2. Buat kelas penyedia adaptor yang mengimplementasikan IValidationAttributeAdapterProvider. Dalam metode berikan atribut kustom ke konstruktor adaptor, seperti yang GetAttributeAdapter ditunjukkan dalam contoh ini:

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter? GetAttributeAdapter(
            ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. Daftarkan penyedia adaptor untuk DI di Program.cs:

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovieWithClientValidator atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  • Dalam atribut validasi kustom, terapkan IClientModelValidator antarmuka dan buat AddValidation metode . Dalam metode , AddValidation tambahkan data- atribut untuk validasi, seperti yang ditunjukkan dalam contoh berikut:

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
            => Year = year;
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult? IsValid(
            object? value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value!).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

Menonaktifkan validasi sisi klien

Kode berikut menonaktifkan validasi klien di Razor Pages:

builder.Services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

Opsi lain untuk menonaktifkan validasi sisi klien:

  • Komentari referensi ke _ValidationScriptsPartial dalam semua .cshtml file.
  • Hapus konten file Pages\Shared_ValidationScriptsPartial.cshtml .

Pendekatan sebelumnya tidak akan mencegah validasi sisi klien ASP.NET IdentityRazor Core Class Library. Untuk informasi selengkapnya, lihat Perancah Identity dalam proyek ASP.NET Core.

Sumber Daya Tambahan:

Artikel ini menjelaskan cara memvalidasi input pengguna di aplikasi ASP.NET Core MVC atau Razor Pages.

Lihat atau unduh sampel kode (cara mengunduh).

Status model

Status model mewakili kesalahan yang berasal dari dua subsistem: pengikatan model dan validasi model. Kesalahan yang berasal dari pengikatan model umumnya adalah kesalahan konversi data. Misalnya, "x" dimasukkan dalam bidang bilangan bulat. Validasi model terjadi setelah pengikatan model dan melaporkan kesalahan di mana data tidak sesuai dengan aturan bisnis. Misalnya, 0 dimasukkan dalam bidang yang mengharapkan peringkat antara 1 dan 5.

Pengikatan model dan validasi model terjadi sebelum eksekusi tindakan pengontrol atau Razor metode handler Pages. Untuk aplikasi web, aplikasi bertanggung jawab untuk memeriksa ModelState.IsValid dan bereaksi dengan tepat. Aplikasi web biasanya memutar ulang halaman dengan pesan kesalahan:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Pengontrol API Web tidak perlu memeriksa apakah ModelState.IsValid mereka memiliki atribut [ApiController ]. Dalam hal ini, respons HTTP 400 otomatis yang berisi detail kesalahan dikembalikan ketika status model tidak valid. Untuk informasi selengkapnya, lihat Respons HTTP 400 otomatis.

Menjalankan ulang validasi

Validasi otomatis, tetapi Anda mungkin ingin mengulanginya secara manual. Misalnya, Anda mungkin menghitung nilai untuk properti dan ingin menjalankan ulang validasi setelah mengatur properti ke nilai komputasi. Untuk menjalankan kembali validasi, panggil ModelStateDictionary.ClearValidationState untuk menghapus validasi khusus untuk model yang sedang divalidasi diikuti oleh TryValidateModel:

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Atribut validasi

Atribut validasi memungkinkan Anda menentukan aturan validasi untuk properti model. Contoh berikut dari aplikasi sampel menunjukkan kelas model yang diannotasikan dengan atribut validasi. Atribut [ClassicMovie] adalah atribut validasi kustom dan yang lain dibangun. Tidak ditampilkan adalah [ClassicMovieWithClientValidator], yang menunjukkan cara alternatif untuk mengimplementasikan atribut kustom.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Atribut bawaan

Berikut adalah beberapa atribut validasi bawaan:

  • [ValidateNever]: Menunjukkan bahwa properti atau parameter harus dikecualikan dari validasi.
  • [CreditCard]: Memvalidasi bahwa properti memiliki format kartu kredit. Memerlukan Metode Tambahan Validasi jQuery.
  • [Bandingkan]: Memvalidasi bahwa dua properti dalam kecocokan model.
  • [EmailAddress]: Memvalidasi bahwa properti memiliki format email.
  • [Telepon]: Memvalidasi bahwa properti memiliki format nomor telepon.
  • [Rentang]: Memvalidasi bahwa nilai properti berada dalam rentang tertentu.
  • [RegularExpression]: Memvalidasi bahwa nilai properti cocok dengan ekspresi reguler tertentu.
  • [Wajib]: Memvalidasi bahwa bidang tidak null. Lihat [Required] atribut untuk detail tentang perilaku atribut ini.
  • [StringLength]: Memvalidasi bahwa nilai properti string tidak melebihi batas panjang yang ditentukan.
  • [Url]: Memvalidasi bahwa properti memiliki format URL.
  • [Remote]: Memvalidasi input pada klien dengan memanggil metode tindakan di server. Lihat [Remote] atribut untuk detail tentang perilaku atribut ini.

Daftar lengkap atribut validasi dapat ditemukan di System.ComponentModel.DataAnnotations namespace layanan.

Pesan kesalahan

Atribut validasi memungkinkan Anda menentukan pesan kesalahan yang akan ditampilkan untuk input yang tidak valid. Contohnya:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Secara internal, atribut memanggil String.Format dengan tempat penampung untuk nama bidang dan terkadang tempat penampung tambahan. Contohnya:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Saat diterapkan ke properti, pesan kesalahan yang Name dibuat oleh kode sebelumnya adalah "Panjang nama harus antara 6 dan 8.".

Untuk mengetahui parameter mana yang diteruskan untuk String.Format pesan kesalahan atribut tertentu, lihat kode sumber DataAnnotations.

Jenis referensi yang tidak dapat diubah ke null dan atribut [Wajib]

Sistem validasi memperlakukan parameter yang tidak dapat diubah ke null atau properti terikat seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Dengan mengaktifkan Nullable konteks, MVC secara implisit mulai memvalidasi properti atau parameter yang tidak dapat diubah ke null seolah-olah telah dikaitkan dengan [Required(AllowEmptyStrings = true)] atribut . Pertimbangkan gambar berikut:

public class Person
{
    public string Name { get; set; }
}

Jika aplikasi dibuat dengan <Nullable>enable</Nullable>, nilai yang hilang untuk Name di JSON atau posting formulir menghasilkan kesalahan validasi. Gunakan tipe referensi nullable untuk memperbolehkan nilai null atau hilang ditentukan untuk Name properti:

public class Person
{
    public string? Name { get; set; }
}

Perilaku ini dapat dinonaktifkan dengan mengonfigurasi SuppressImplicitRequiredAttributeForNonNullableReferenceTypes di Startup.ConfigureServices:

services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Validasi [wajib] pada server

Pada server, nilai yang diperlukan dianggap hilang jika properti null. Bidang yang tidak dapat diubah ke null selalu valid, dan [Required] pesan kesalahan atribut tidak pernah ditampilkan.

Namun, pengikatan model untuk properti yang tidak dapat diubah ke null mungkin gagal, mengakibatkan pesan kesalahan seperti The value '' is invalid. Untuk menentukan pesan kesalahan kustom untuk validasi sisi server dari jenis yang tidak dapat diubah ke null, Anda memiliki opsi berikut:

  • Buat bidang nullable (misalnya, decimal? bukan decimal). Jenis nilai T> nullable<diperlakukan seperti jenis nullable standar.

  • Tentukan pesan kesalahan default yang akan digunakan oleh pengikatan model, seperti yang ditunjukkan dalam contoh berikut:

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

    Untuk informasi selengkapnya tentang kesalahan pengikatan model yang dapat Anda atur pesan defaultnya, lihat DefaultModelBindingMessageProvider.

Validasi [Wajib] pada klien

Jenis dan string yang tidak dapat diubah ke null ditangani secara berbeda pada klien dibandingkan dengan server. Di klien:

  • Nilai dianggap hanya ada jika input dimasukkan untuknya. Oleh karena itu, validasi sisi klien menangani jenis yang tidak dapat diubah ke null sama dengan jenis nullable.
  • Spasi kosong dalam bidang string dianggap sebagai input yang valid oleh metode yang diperlukan Validasi jQuery. Validasi sisi server menganggap bidang string yang diperlukan tidak valid jika hanya spasi kosong yang dimasukkan.

Seperti disebutkan sebelumnya, jenis yang tidak dapat diubah ke null diperlakukan seolah-olah mereka memiliki [Required(AllowEmptyStrings = true)] atribut. Itu berarti Anda mendapatkan validasi sisi klien meskipun Anda tidak menerapkan [Required(AllowEmptyStrings = true)] atribut . Tetapi jika Anda tidak menggunakan atribut , Anda mendapatkan pesan kesalahan default. Untuk menentukan pesan kesalahan kustom, gunakan atribut .

Atribut [Remote]

Atribut [Remote] mengimplementasikan validasi sisi klien yang mengharuskan memanggil metode di server untuk menentukan apakah input bidang valid. Misalnya, aplikasi mungkin perlu memverifikasi apakah nama pengguna sudah digunakan.

Untuk menerapkan validasi jarak jauh:

  1. Buat metode tindakan untuk dipanggil JavaScript. Metode jarak jauh Validasi jQuery mengharapkan JSrespons ON:

    • true berarti data input valid.
    • false, undefined, atau null berarti input tidak valid. Tampilkan pesan kesalahan default.
    • String lainnya berarti input tidak valid. Tampilkan string sebagai pesan kesalahan kustom.

    Berikut adalah contoh metode tindakan yang mengembalikan pesan kesalahan kustom:

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Di kelas model, anotasi properti dengan [Remote] atribut yang menunjuk ke metode tindakan validasi, seperti yang ditunjukkan dalam contoh berikut:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; }
    

Bidang tambahan

Properti AdditionalFields[Remote] atribut memungkinkan Anda memvalidasi kombinasi bidang terhadap data di server. Misalnya, jika User model memiliki FirstName properti dan LastName , Anda mungkin ingin memverifikasi bahwa tidak ada pengguna yang sudah memiliki sepasang nama tersebut. Contoh berikut menunjukkan cara menggunakan AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; }

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; }

AdditionalFields dapat diatur secara eksplisit ke string "FirstName" dan "LastName", tetapi menggunakan operator nameof menyederhanakan pemfaktoran ulang nanti. Metode tindakan untuk validasi ini harus menerima argumen firstName dan lastName :

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

Saat pengguna memasukkan nama depan atau belakang, JavaScript melakukan panggilan jarak jauh untuk melihat apakah pasangan nama tersebut telah diambil.

Untuk memvalidasi dua atau beberapa bidang tambahan, berikan sebagai daftar yang dibatasi koma. Misalnya, untuk menambahkan MiddleName properti ke model, atur [Remote] atribut seperti yang ditunjukkan dalam contoh berikut:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, seperti semua argumen atribut, harus berupa ekspresi konstan. Oleh karena itu, jangan gunakan string atau panggilan Join terinterpolasi untuk menginisialisasi AdditionalFields .

Alternatif untuk atribut bawaan

Jika Anda memerlukan validasi yang tidak disediakan oleh atribut bawaan, Anda dapat:

Mengelola atribut kustom

Untuk skenario yang tidak ditangani atribut validasi bawaan, Anda dapat membuat atribut validasi kustom. Buat kelas yang mewarisi dari ValidationAttribute, dan ambil alih IsValid metode .

Metode IsValid menerima objek bernama value, yang merupakan input yang akan divalidasi. Kelebihan beban juga menerima ValidationContext objek, yang menyediakan informasi tambahan, seperti instans model yang dibuat oleh pengikatan model.

Contoh berikut memvalidasi bahwa tanggal rilis untuk film dalam genre Klasik tidak lebih dari tahun yang ditentukan. Atribut [ClassicMovie] :

  • Hanya dijalankan di server.
  • Untuk film Klasik, memvalidasi tanggal rilis:
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
    {
        Year = year;
    }

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

Variabel movie dalam contoh sebelumnya mewakili Movie objek yang berisi data dari pengiriman formulir. Saat validasi gagal, dengan ValidationResult pesan kesalahan dikembalikan.

IValidatableObject

Contoh sebelumnya hanya berfungsi dengan Movie jenis. Opsi lain untuk validasi tingkat kelas adalah menerapkan IValidatableObject di kelas model, seperti yang ditunjukkan dalam contoh berikut:

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

Validasi simpul tingkat atas

Simpul tingkat atas meliputi:

  • Parameter Tindakan
  • Properti pengontrol
  • Parameter handler halaman
  • Properti model halaman

Simpul tingkat atas yang terikat model divalidasi selain memvalidasi properti model. Dalam contoh berikut dari aplikasi sampel, VerifyPhone metode menggunakan RegularExpressionAttribute untuk memvalidasi phone parameter tindakan:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Simpul tingkat atas dapat digunakan BindRequiredAttribute dengan atribut validasi. Dalam contoh berikut dari aplikasi sampel, CheckAge metode menentukan bahwa age parameter harus terikat dari string kueri saat formulir dikirimkan:

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Di halaman Periksa Usia (CheckAge.cshtml), ada dua formulir. Formulir pertama mengirimkan Age nilai 99 sebagai parameter string kueri: https://localhost:5001/Users/CheckAge?Age=99.

Saat parameter yang diformat age dengan benar dari string kueri dikirimkan, formulir memvalidasi.

Formulir kedua pada halaman Periksa Usia mengirimkan Age nilai dalam isi permintaan, dan validasi gagal. Pengikatan gagal karena age parameter harus berasal dari string kueri.

Kesalahan maksimum

Validasi berhenti ketika jumlah maksimum kesalahan tercapai (200 secara default). Anda dapat mengonfigurasi nomor ini dengan kode berikut di Startup.ConfigureServices:

services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

services.AddSingleton<IValidationAttributeAdapterProvider,
    CustomValidationAttributeAdapterProvider>();

Rekursi maksimum

ValidationVisitor melintasi grafik objek model yang sedang divalidasi. Untuk model yang dalam atau rekursif tanpa batas, validasi dapat mengakibatkan luapan tumpukan. MvcOptions.MaxValidationDepth menyediakan cara untuk menghentikan validasi lebih awal jika rekursi pengunjung melebihi kedalaman yang dikonfigurasi. Nilai default adalah MvcOptions.MaxValidationDepth 32.

Sirkuit pendek otomatis

Validasi secara otomatis memiliki sirkuit pendek (dilewati) jika grafik model tidak memerlukan validasi. Objek yang dilewati runtime validasi untuk menyertakan koleksi primitif (seperti byte[], , string[]Dictionary<string, string>) dan grafik objek kompleks yang tidak memiliki validator apa pun.

Validasi sisi klien

Validasi sisi klien mencegah pengiriman hingga formulir valid. Tombol Kirim menjalankan JavaScript yang mengirimkan formulir atau menampilkan pesan kesalahan.

Validasi sisi klien menghindari perjalanan pulang pergi yang tidak perlu ke server ketika ada kesalahan input pada formulir. Referensi skrip berikut dalam _Layout.cshtml dan _ValidationScriptsPartial.cshtml mendukung validasi sisi klien:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js"></script>

Skrip Validasi jQuery Unobtrusive adalah pustaka front-end Microsoft kustom yang dibangun pada plugin Validasi jQuery populer. Tanpa Validasi jQuery Unobtrusive, Anda harus mengodekan logika validasi yang sama di dua tempat: sekali di atribut validasi sisi server pada properti model, dan kemudian lagi dalam skrip sisi klien. Sebagai gantinya, Pembantu Tag dan pembantu HTML menggunakan atribut validasi dan mengetik metadata dari properti model untuk merender atribut HTML 5 data- untuk elemen formulir yang memerlukan validasi. jQuery Unobtrusive Validation mengurai data- atribut dan meneruskan logika ke Validasi jQuery, secara efektif "menyalin" logika validasi sisi server ke klien. Anda dapat menampilkan kesalahan validasi pada klien menggunakan pembantu tag seperti yang ditunjukkan di sini:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

Pembantu tag sebelumnya merender HTML berikut:

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

Perhatikan bahwa data- atribut dalam output HTML sesuai dengan atribut validasi untuk Movie.ReleaseDate properti . Atribut data-val-required berisi pesan kesalahan untuk ditampilkan jika pengguna tidak mengisi bidang tanggal rilis. jQuery Unobtrusive Validation meneruskan nilai ini ke metode jQuery Validation required(), yang kemudian menampilkan pesan tersebut dalam elemen rentang> yang <menyertainya.

Validasi jenis data didasarkan pada jenis .NET properti, kecuali jika ditimpa oleh atribut [DataType ]. Browser memiliki pesan kesalahan default mereka sendiri, tetapi paket Validasi jQuery Validation Tidak Mengganggu dapat mengambil alih pesan tersebut. [DataType] atribut dan subkelas seperti [EmailAddress] memungkinkan Anda menentukan pesan kesalahan.

Validasi tidak mengganggu

Untuk informasi tentang validasi yang tidak mengganggu, lihat masalah GitHub ini.

Menambahkan Validasi ke Formulir Dinamis

jQuery Unobtrusive Validation meneruskan logika validasi dan parameter ke Validasi jQuery saat halaman pertama kali dimuat. Oleh karena itu, validasi tidak berfungsi secara otomatis pada formulir yang dihasilkan secara dinamis. Untuk mengaktifkan validasi, beri tahu jQuery Unobtrusive Validation untuk mengurai formulir dinamis segera setelah Anda membuatnya. Misalnya, kode berikut menyiapkan validasi sisi klien pada formulir yang ditambahkan melalui AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

Metode $.validator.unobtrusive.parse() menerima pemilih jQuery untuk satu argumennya. Metode ini memberi tahu jQuery Unobtrusive Validation untuk mengurai atribut formulir dalam pemilih tersebut data- . Nilai atribut tersebut kemudian diteruskan ke plugin Validasi jQuery.

Menambahkan Validasi ke Kontrol Dinamis

Metode ini $.validator.unobtrusive.parse() bekerja pada seluruh formulir, bukan pada kontrol yang dihasilkan secara dinamis individu, seperti <input> dan <select/>. Untuk memilah ulang formulir, hapus data validasi yang ditambahkan saat formulir diurai sebelumnya, seperti yang ditunjukkan dalam contoh berikut:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Validasi sisi klien kustom

Validasi sisi klien kustom dilakukan dengan menghasilkan data- atribut HTML yang berfungsi dengan adaptor Validasi jQuery kustom. Contoh kode adaptor berikut ditulis untuk [ClassicMovie] atribut dan [ClassicMovieWithClientValidator] yang diperkenalkan sebelumnya dalam artikel ini:

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

Untuk informasi tentang cara menulis adaptor, lihat dokumentasi Validasi jQuery.

Penggunaan adaptor untuk bidang tertentu dipicu oleh data- atribut yang:

  • Benderai bidang sebagai tunduk pada validasi (data-val="true").
  • Identifikasi nama aturan validasi dan teks pesan kesalahan (misalnya, data-val-rulename="Error message.").
  • Berikan parameter tambahan apa pun yang dibutuhkan validator (misalnya, data-val-rulename-param1="value").

Contoh berikut menunjukkan data- atribut untuk atribut aplikasiClassicMovie sampel:

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

Seperti disebutkan sebelumnya, Pembantu Tag dan pembantu HTML menggunakan informasi dari atribut validasi untuk merender data- atribut. Ada dua opsi untuk menulis kode yang menghasilkan pembuatan atribut HTML kustom data- :

  • Buat kelas yang berasal dari AttributeAdapterBase<TAttribute> dan kelas yang mengimplementasikan IValidationAttributeAdapterProvider, dan daftarkan atribut Anda dan adaptornya di DI. Metode ini mengikuti prinsip tanggung jawab tunggal dalam kode validasi terkait server dan terkait klien berada di kelas terpisah. Adaptor juga memiliki keuntungan bahwa karena terdaftar di DI, layanan lain di DI tersedia untuk itu jika diperlukan.
  • Terapkan IClientModelValidator di kelas Anda ValidationAttribute . Metode ini mungkin sesuai jika atribut tidak melakukan validasi sisi server apa pun dan tidak memerlukan layanan apa pun dari DI.

AttributeAdapter untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovie atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  1. Buat kelas adaptor atribut untuk atribut validasi kustom. Dapatkan kelas dari AttributeAdapterBase<TAttribute>. Buat metode yang menambahkan data- atribut ke output yang dirender, seperti yang AddValidation ditunjukkan dalam contoh ini:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute,
            IStringLocalizer stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext) =>
            Attribute.GetErrorMessage();
    }
    
  2. Buat kelas penyedia adaptor yang mengimplementasikan IValidationAttributeAdapterProvider. Dalam metode berikan atribut kustom ke konstruktor adaptor, seperti yang GetAttributeAdapter ditunjukkan dalam contoh ini:

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute,
            IStringLocalizer stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. Daftarkan penyedia adaptor untuk DI di Startup.ConfigureServices:

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator untuk validasi sisi klien

Metode penyajian data- atribut dalam HTML ini digunakan oleh ClassicMovieWithClientValidator atribut di aplikasi sampel. Untuk menambahkan validasi klien dengan menggunakan metode ini:

  • Dalam atribut validasi kustom, terapkan IClientModelValidator antarmuka dan buat AddValidation metode . Dalam metode , AddValidation tambahkan data- atribut untuk validasi, seperti yang ditunjukkan dalam contoh berikut:

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
        {
            Year = year;
        }
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult IsValid(object value,
            ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

Menonaktifkan validasi sisi klien

Kode berikut menonaktifkan validasi klien di Razor Pages:

services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

Opsi lain untuk menonaktifkan validasi sisi klien:

  • Komentari referensi ke _ValidationScriptsPartial dalam semua .cshtml file.
  • Hapus konten file Pages\Shared_ValidationScriptsPartial.cshtml .

Pendekatan sebelumnya tidak akan mencegah validasi sisi klien ASP.NET IdentityRazor Core Class Library. Untuk informasi selengkapnya, lihat Perancah Identity dalam proyek ASP.NET Core.

Sumber Daya Tambahan: