[ASP.NET MVC] 新增資料驗證

[ASP.NET MVC] 在Model中加入資料驗證

新增驗證

開啟Movie.cs檔,看到最上方中引用了System.ComponentModel.DataAnnotations

DataAnnotations提供內建的資料驗證用於Class與屬性中,也提供資料格式設定,如DataType能夠定義資料的格式。 

接著,在Movie Class加入內建的資料驗證,修改Movie Class如下:

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

    [StringLength(60,MinimumLength=3)]
    public string Title { get; set; }

    [Display(Name = "日期")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(30)]
    public string Genre { get; set; }
    
    [Range(1, 1000)]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

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

StringLength屬性設定字串的最大長度(MinimumLength則是最小長度)。

伺服器總管Movies資料表點右鍵>選擇開啟資料表定義

開啟的資料表定義:

在上面的資料表定義可以看到所有的字串都還是設為NVARCHAR  (MAX)

接著,開啟套件管理器主控台,在視窗中輸入下列指令來更新架構:

add-migration DataAnnotations
update-database

指令執行完畢後,Visual Studio會開啟一個名為日期_DataAnnotations的Class檔案,檔案中定義了新的DbMigration以及更新資料架構的Up方法 。

public override void Up()
{
    AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
    AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
    AlterColumn("dbo.Movies", "Rating", c => c.String(nullable: false, maxLength: 5));
}

Genre欄位將不是nullable(必須輸入一個值),Rating的最大長度為5,Title的最大長度為60。

而Title的最小長度為3與Price的範圍並沒有產生架構的變更。 

檢視Movie的資料表定義:

資料表定義中可以看到新的長度限制,以及Genre和Rating欄位的Allow Nulls取消勾選了。 

資料屬性驗證可以強制Model屬性的應用。

例如:

Required:表示該屬性為必要的,不能為空。

MinimumLength:則表示最小長度為3 。

Range:限制該值的範圍

StringLength:用於設定字串的最大長度與最小長度

 

Code First會在應用程式保存變更到資料庫之前,執行Model Class的驗證規則,驗證資料格式是否正確。

例如,在ControllerPOST方法中的 db.SaveChanges() 會在資料缺失時拋出錯誤訊息:

藉由.NET Framework自動強制驗證規則的幫助,讓你的應用程式更加全面。也確保不會忘記驗證而讓一些錯誤的資料進到資料庫裡。

 

ASP.NET MVC的驗證介面

執行應用程式,並瀏覽到/Movies頁面。

點擊Create New連結,並新增一個新的電影。在表格中輸入一些無效的值,只要jQuery的客戶端驗證偵測到錯誤,便會在頁面上顯示錯誤訊息。

可以看到在欄位中有無效值的時候,會在欄位下方顯示錯誤訊息。錯誤訊息執行於客戶端(使用JavaScript與jQuery)與伺服器端(當使用者關閉JavaScript時)。

Controller與View會經自動提取在Movie Model Class裡的屬性驗證。這樣便不用為了驗證資料,而分別修改MoviesController Class或是Create.cshtml。

當資料有錯誤時,表格中的資料不會發送到伺服器,直到客戶端沒有驗證錯誤為止。

試著編輯電影,可以看到相同的資料驗證。

 

資料驗證的運作

在沒有更新Controller與View的程式碼的情況下,是如何產生資料驗證的呢?

MovieController ClassCreat方法與建立時一樣,沒有任何改變:

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

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(movie);
}

第一個 (HTTP GET) Create 方法顯示初始的Create表格,第二個([HttpPost])Create方法處理表格的POST動作。

第二個Create方法([HttpPost])呼叫ModelState.IsValid來檢查輸入的電影資料是否有驗證上的錯誤,如果沒有驗證錯誤才會將新的電影儲存到資料庫中。

客戶端驗證錯誤時,資料不會POST到伺服器端呼叫HttpPost的Create方法。

如果在瀏覽器關閉JavaScript,那麼客戶端的驗證將會關閉。資料會POST到伺服器端呼叫HttpPost的Create方法,ModelState.IsValid則會在這個時候驗證資料是否有錯誤。

在HttpPost Create設中斷點確認方法不會被呼叫到。接著關閉瀏覽器中的JavaScript,那麼錯誤的資料便會遞交到伺服器端,並執行到Create方法的中斷點。

不過雖然錯誤的資料被傳送到伺服器端,但是仍然能有ModelState.IsValid的資料驗證。

在IE關閉JavaScript:

在Chrome關閉JavaScript:

若關閉JavaScript便會執行HttpPost的Create方法:

Create.cshtml 中,會依照Create方法而顯示初始的表單或是在有驗證錯誤的時候顯示錯誤訊息。

程式碼中使用Html.EditorFor輸出每個電影屬性的<input>元素。 而Html.ValidationMessageFor則會在資料驗證有錯誤時顯示錯誤訊息。

這兩個HtmlHelper方法作用於Controller傳送到View的Movie Model,並自動檢視Model的驗證屬性來適當的顯示錯誤訊息。

不論是Controller或是View都能透過Movie Class的規則進行驗證與顯示相對應的錯誤訊息。Movie Class的驗證規則也可以應用在編輯(Edit )的View以及其它會新增或是修改Model的View。

因此,要是想修改驗證規則只需要修改Movie的Model就好,不用再修改其他地方。所有的驗證邏輯都會被定義在Model中,並應用在任何地方。

這能夠讓程式碼變得乾淨簡單,更容易維護。

 

DataType 屬性

開啟Movie.cs檔並檢視Movie Class,頂端的命名空間System.ComponentModel.DataAnnotations除了提供驗證屬性也提供格式的屬性。

在先前已經對於日期與價格(Price)做DataType的應用,如下面的程式碼:

[Display(Name = "日期")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

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

DataType屬性提供資料格式給View,除了上面的DataType.Date與DataType.Currency外,還有以下格式:

[DataType(DataType.EmailAddress)]  //Mail格式
[DataType(DataType.PhoneNumber)]   //電話格式
[DataType(DataType.Url)]           //Url格式

DataType屬性並不會提供資料驗證。可以RegularExpression屬性來進行驗證,如下列程式碼規定只能輸入規定的文字:

[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]

DataType屬性可以指出比資料庫更明確的資料格式,但不提供資料驗證。

在Movie Class中的日期格式中只顯示日期而不顯時間。

DataType提供多種的資料型態,如:日期、時間、電話、貨幣、郵件地址...等。

DataType還可以讓應用程式自動提供特定類型的功能,例如要產生一個郵件連結可以用DataType.EmailAddress,日期選擇則可以用DataType.Date來表達HTML5type="date"

DataType.Date並沒有指定日期的格式,可以使用DisplayFormat來指定日期的格式:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }

DisplayFormat可以定義資料的格式,但是不指定DisplayFormat的屬性也有好處,在預設下瀏覽器會依照目前得語言環境使用最適當的格式。

Movie Class中的屬性也可以結合寫在一列:

 

下一篇  檢視Details與Delete

 

 END 

回目錄