Bagikan melalui


Menambahkan Logika Validasi ke Model Film

oleh Rick Anderson

Catatan

Versi terbaru dari tutorial ini tersedia di sini yang menggunakan ASP.NET MVC 5 dan Visual Studio 2013. Lebih aman, jauh lebih mudah untuk diikuti dan menunjukkan lebih banyak fitur.

Di bagian ini Anda akan menambahkan logika validasi ke Movie model, dan Anda akan memastikan bahwa aturan validasi diberlakukan setiap kali pengguna mencoba membuat atau mengedit film menggunakan aplikasi.

Menjaga Hal-hal TETAP KERING

Salah satu tenet desain inti ASP.NET MVC adalah DRY ("Don't Repeat Yourself"). ASP.NET MVC mendorong Anda untuk menentukan fungsionalitas atau perilaku hanya sekali, dan kemudian membuatnya tercermin di mana-mana dalam aplikasi. Ini mengurangi jumlah kode yang perlu Anda tulis dan membuat kode yang Anda tulis lebih sedikit rawan kesalahan dan lebih mudah dipertahankan.

Dukungan validasi yang diberikan oleh ASP.NET MVC dan Entity Framework Code First adalah contoh yang bagus dari prinsip DRY yang sedang berjalan. Anda dapat secara deklaratif menentukan aturan validasi di satu tempat (di kelas model) dan aturan diberlakukan di mana saja dalam aplikasi.

Mari kita lihat bagaimana Anda dapat memanfaatkan dukungan validasi ini di aplikasi film.

Menambahkan Aturan Validasi ke Model Film

Anda akan mulai dengan menambahkan beberapa logika validasi ke Movie kelas .

Buka file Movie.cs. using Tambahkan pernyataan di bagian atas file yang mereferensikan System.ComponentModel.DataAnnotations namespace:

using System.ComponentModel.DataAnnotations;

Perhatikan bahwa namespace tidak berisi System.Web. DataAnnotations menyediakan sekumpulan atribut validasi bawaan yang dapat Anda terapkan secara deklaratif ke kelas atau properti apa pun.

Sekarang perbarui Movie kelas untuk memanfaatkan atribut validasi bawaan Required, StringLength, dan Range . Gunakan kode berikut sebagai contoh tempat menerapkan atribut.

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

    [Required]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    public string Genre { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

Jalankan aplikasi dan Anda akan kembali mendapatkan kesalahan run time berikut:

Model yang mendukung konteks 'MovieDBContext' telah berubah sejak database dibuat. Pertimbangkan untuk menggunakan Migrasi Pertama Kode untuk memperbarui database (https://go.microsoft.com/fwlink/?LinkId=238269).

Kami akan menggunakan migrasi untuk memperbarui skema. Bangun solusi, lalu buka jendela Konsol Manajer Paket dan masukkan perintah berikut:

add-migration AddDataAnnotationsMig
update-database

Setelah perintah ini selesai, Visual Studio membuka file kelas yang menentukan kelas turunan baru DbMigration dengan nama yang ditentukan (AddDataAnnotationsMig), dan dalam metode Anda Up dapat melihat kode yang memperbarui batasan skema. Bidang Title dan Genre tidak lagi dapat diubah ke null (yaitu, Anda harus memasukkan nilai) dan Rating bidang memiliki panjang maksimum 5.

Atribut validasi menentukan perilaku yang ingin Anda terapkan pada properti model yang diterapkan. Atribut Required menunjukkan bahwa properti harus memiliki nilai; dalam sampel ini, film harus memiliki nilai untuk Titleproperti , , ReleaseDateGenre, dan Price agar valid. Atribut Range membatasi nilai dalam rentang yang ditentukan. Atribut ini StringLength memungkinkan Anda mengatur panjang maksimum properti string, dan secara opsional panjang minimumnya. Jenis intrinsik (seperti decimal, int, float, DateTime) diperlukan secara default dan tidak memerlukan Required atribut .

Code First memastikan bahwa aturan validasi yang Anda tentukan pada kelas model diberlakukan sebelum aplikasi menyimpan perubahan dalam database. Misalnya, kode di bawah ini akan melemparkan pengecualian ketika metode dipanggil SaveChanges , karena beberapa nilai properti yang diperlukan Movie hilang dan harganya nol (yang berada di luar rentang yang valid).

MovieDBContext db = new MovieDBContext();

Movie movie = new Movie();
movie.Title = "Gone with the Wind";
movie.Price = 0.0M;

db.Movies.Add(movie);  
db.SaveChanges();        // <= Will throw server side validation exception  

Memiliki aturan validasi yang secara otomatis diberlakukan oleh .NET Framework membantu membuat aplikasi Anda lebih kuat. Ini juga memastikan bahwa Anda tidak bisa lupa untuk memvalidasi sesuatu dan secara tidak sengaja membiarkan data buruk ke dalam database.

Berikut adalah daftar kode lengkap untuk file Movie.cs yang diperbarui:

using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models {
    public class Movie {
        public int ID { get; set; }

        [Required]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Required]
        public string Genre { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }
    }

    public class MovieDBContext : DbContext {
        public DbSet<Movie> Movies { get; set; }
    }
}

UI Kesalahan Validasi di MVC ASP.NET

Jalankan kembali aplikasi dan navigasikan ke URL /Movies .

Klik tautan Buat Baru untuk menambahkan film baru. Isi formulir dengan beberapa nilai yang tidak valid lalu klik tombol Buat .

8_validationErrors

Catatan

untuk mendukung validasi jQuery untuk lokal non-Bahasa Inggris yang menggunakan koma (",") untuk titik desimal, Anda harus menyertakan globalize.js dan budaya/globalize.cultures.js file spesifik Anda(dari https://github.com/jquery/globalize ) dan JavaScript untuk menggunakan Globalize.parseFloat. Kode berikut menunjukkan modifikasi pada file Views\Movies\Edit.cshtml untuk bekerja dengan budaya "fr-FR":

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/globalize.js"></script>
    <script src="~/Scripts/globalize.culture.fr-FR.js"></script>
    <script>
        $.validator.methods.number = function (value, element) {
            return this.optional(element) ||
                !isNaN(Globalize.parseFloat(value));
        }
        $(document).ready(function () {
            Globalize.culture('fr-FR');
        });
    </script>
    <script>
        jQuery.extend(jQuery.validator.methods, {    
            range: function (value, element, param) {        
                //Use the Globalization plugin to parse the value        
                var val = $.global.parseFloat(value);
                return this.optional(element) || (
                    val >= param[0] && val <= param[1]);
            }
        });

    </script>
}

Perhatikan bagaimana formulir telah secara otomatis menggunakan warna batas merah untuk menyoroti kotak teks yang berisi data yang tidak valid dan telah memancarkan pesan kesalahan validasi yang sesuai di samping masing-masing kotak teks. Kesalahan diberlakukan baik sisi klien (menggunakan JavaScript dan jQuery) dan sisi server (jika pengguna menonaktifkan JavaScript).

Manfaat nyata adalah Anda tidak perlu mengubah satu baris kode di MoviesController kelas atau dalam tampilan Create.cshtml untuk mengaktifkan UI validasi ini. Pengontrol dan tampilan yang Anda buat sebelumnya dalam tutorial ini secara otomatis mengambil aturan validasi yang Anda tentukan dengan menggunakan atribut validasi pada properti Movie kelas model.

Anda mungkin telah memperhatikan properti Title dan Genre, atribut yang diperlukan tidak diberlakukan sampai Anda mengirimkan formulir (tekan tombol Buat ), atau masukkan teks ke bidang input dan menghapusnya. Untuk bidang yang awalnya kosong (seperti bidang pada tampilan Buat) dan yang hanya memiliki atribut yang diperlukan dan tidak ada atribut validasi lainnya, Anda dapat melakukan hal berikut untuk memicu validasi:

  1. Tab ke bidang .
  2. Masukkan beberapa teks.
  3. Tab keluar.
  4. Tab kembali ke bidang .
  5. Hapus teks.
  6. Tab keluar.

Urutan di atas akan memicu validasi yang diperlukan tanpa menekan tombol kirim. Cukup tekan tombol kirim tanpa memasukkan salah satu bidang akan memicu validasi sisi klien. Data formulir tidak dikirim ke server sampai tidak ada kesalahan validasi sisi klien. Anda dapat menguji ini dengan menempatkan titik henti dalam metode HTTP Post atau menggunakan alat fiddler atau alat pengembang IE 9 F12.

Cuplikan layar yang memperlihatkan halaman M V C Movie Create. Pemberitahuan di samping Judul menyatakan bahwa bidang Judul diperlukan. Pemberitahuan di samping Genre menyatakan bahwa bidang Genre diperlukan.

Bagaimana Validasi Terjadi dalam Buat Tampilan dan Buat Metode Tindakan

Anda mungkin bertanya-tanya bagaimana UI validasi dihasilkan tanpa pembaruan kode di pengontrol atau tampilan. Daftar berikutnya menunjukkan seperti apa Create metode di MovieController kelas tersebut. Mereka tidak berubah dari cara Anda membuatnya sebelumnya dalam tutorial ini.

//
// GET: /Movies/Create

public ActionResult Create()
{
    return View();
}

//
// POST: /Movies/Create

[HttpPost]
public ActionResult Create(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(movie);
}

Metode tindakan pertama (HTTP GET) Create menampilkan formulir Buat awal. Versi kedua ([HttpPost]) menangani posting formulir. Metode kedua Create (Versi HttpPost ) memanggil ModelState.IsValid untuk memeriksa apakah film memiliki kesalahan validasi. Memanggil metode ini mengevaluasi atribut validasi apa pun yang telah diterapkan ke objek. Jika objek memiliki kesalahan validasi, Create metode akan menampilkan kembali formulir. Jika tidak ada kesalahan, metode menyimpan film baru dalam database. Dalam contoh film kami yang kami gunakan, formulir tidak diposting ke server ketika ada kesalahan validasi yang terdeteksi di sisi klien; metode kedua Createtidak pernah dipanggil. Jika Anda menonaktifkan JavaScript di browser Anda, validasi klien dinonaktifkan dan metode HTTP POST Create memanggil ModelState.IsValid untuk memeriksa apakah film memiliki kesalahan validasi.

Anda dapat mengatur titik henti dalam HttpPost Create metode dan memverifikasi metode tidak pernah dipanggil, validasi sisi klien tidak akan mengirimkan data formulir ketika kesalahan validasi terdeteksi. Jika Anda menonaktifkan JavaScript di browser Anda, kirim formulir dengan kesalahan, titik henti akan tertembak. Anda masih mendapatkan validasi penuh tanpa JavaScript. Gambar berikut menunjukkan cara menonaktifkan JavaScript di Internet Explorer.

Cuplikan layar yang memperlihatkan jendela Opsi Internet terbuka ke tab keamanan. Tingkat kustom dilingkari dengan warna merah. Di jendela Pengaturan Keamanan, Skrip aktif diatur ke nonaktifkan. Bilah gulir dilingkari dengan warna merah.

Cuplikan layar yang memperlihatkan posting H t t p. Jika Titik Status Model Valid disorot.

Gambar berikut menunjukkan cara menonaktifkan JavaScript di browser FireFox.

Cuplikan layar yang memperlihatkan jendela Opsi. Konten dipilih dan Aktifkan Skrip Java dicentang.

Gambar berikut menunjukkan cara menonaktifkan JavaScript dengan browser Chrome.

Cuplikan layar yang memperlihatkan halaman Opsi. Di bawah Hood dipilih dan dilingkari dengan warna merah. Di Pengaturan Konten, Skrip Java diatur ke Izinkan semua situs menjalankan Skrip Java.

Di bawah ini adalah templat tampilan Create.cshtml yang Anda perancah sebelumnya dalam tutorial. Ini digunakan oleh metode tindakan yang ditunjukkan di atas untuk menampilkan formulir awal dan untuk memutarnya kembali jika terjadi kesalahan.

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Movie</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>
        <div class="editor-label">
    @Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Rating)
    @Html.ValidationMessageFor(model => model.Rating)
</div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Perhatikan bagaimana kode menggunakan pembantu Html.EditorFor untuk menghasilkan <input> elemen untuk setiap Movie properti. Di samping pembantu ini adalah panggilan ke metode pembantu Html.ValidationMessageFor . Kedua metode pembantu ini bekerja dengan objek model yang diteruskan oleh pengontrol ke tampilan (dalam hal ini, objek Movie ). Mereka secara otomatis mencari atribut validasi yang ditentukan pada model dan menampilkan pesan kesalahan yang sesuai.

Apa yang benar-benar bagus tentang pendekatan ini adalah bahwa tidak ada pengontrol atau templat Buat tampilan yang tahu apa-apa tentang aturan validasi aktual yang diberlakukan atau tentang pesan kesalahan tertentu yang ditampilkan. Aturan validasi dan string kesalahan hanya ditentukan di Movie kelas . Aturan validasi yang sama ini secara otomatis diterapkan ke tampilan Edit dan templat tampilan lain yang mungkin Anda buat yang mengedit model Anda.

Jika Anda ingin mengubah logika validasi nanti, Anda dapat melakukannya tepat di satu tempat dengan menambahkan atribut validasi ke model (dalam contoh ini, movie kelas ). Anda tidak perlu khawatir tentang berbagai bagian aplikasi yang tidak konsisten dengan bagaimana aturan diberlakukan - semua logika validasi akan didefinisikan di satu tempat dan digunakan di mana-mana. Ini menjaga kode sangat bersih, dan membuatnya mudah untuk dipertahankan dan berkembang. Dan itu berarti bahwa Anda akan sepenuhnya menghormati prinsip DRY.

Menambahkan Pemformatan ke Model Film

Buka file Movie.cs dan periksa Movie kelas . Namespace System.ComponentModel.DataAnnotations menyediakan atribut pemformatan selain kumpulan atribut validasi bawaan. Kami telah menerapkan DataType nilai enumerasi ke tanggal rilis dan ke bidang harga. Kode berikut menunjukkan ReleaseDate properti dan Price dengan atribut yang sesuai DisplayFormat .

[DataType(DataType.Date)] 
public DateTime ReleaseDate { get; set; }

[DataType(DataType.Currency)] 
public decimal Price { get; set; }

Atribut DataType bukan atribut validasi, atribut tersebut digunakan untuk memberi tahu mesin tampilan cara merender HTML. Dalam contoh di atas, DataType.Date atribut menampilkan tanggal film sebagai tanggal saja, tanpa waktu. Misalnya, atribut berikut DataType tidak memvalidasi format data:

[DataType(DataType.EmailAddress)]
[DataType(DataType.PhoneNumber)]
[DataType(DataType.Url)]

Atribut yang tercantum di atas hanya memberikan petunjuk bagi mesin tampilan untuk memformat data (dan menyediakan atribut seperti <> untuk URL dan <href="mailto:EmailAddress.com"> untuk email. Anda dapat menggunakan atribut RegularExpression untuk memvalidasi format data.

Pendekatan alternatif untuk menggunakan DataType atribut , Anda dapat secara eksplisit menetapkan DataFormatString nilai. Kode berikut menunjukkan properti tanggal rilis dengan string format tanggal (yaitu, "d"). Anda akan menggunakan ini untuk menentukan bahwa Anda tidak ingin memiliki waktu sebagai bagian dari tanggal rilis.

[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime ReleaseDate { get; set; }

Kelas lengkap Movie ditunjukkan di bawah ini.

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

    [Required]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    public string Genre { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

Jalankan aplikasi dan telusuri ke Movies pengontrol. Tanggal dan harga rilis diformat dengan baik. Gambar di bawah ini menunjukkan tanggal rilis dan harga menggunakan "fr-FR" sebagai budaya.

8_format_SM

Gambar di bawah ini menunjukkan data yang sama yang ditampilkan dengan budaya default (Inggris AS).

Cuplikan layar yang memperlihatkan halaman Indeks Film M V C dengan empat film tercantum.

Di bagian berikutnya dari seri ini, kita akan meninjau aplikasi dan melakukan beberapa penyempurnaan pada metode dan Delete yang dihasilkan Details secara otomatis.