ASP.NET MVC Data Validation

Data Validation (Input data validate: duyệt/kiểm tra dữ liệu đầu vào) có ý nghĩa quan trọng trong các ứng dụng. Việc validate data không chỉ giúp người dùng có 1 tiêu chuẩn nhập liệu 1 cách tốt hơn, mà còn giúp developer giảm thiểu được lỗi trong quá trình xử lý.

Validate data nên thực hiện ở cả 2 tầng là front-end và back-end, như vậy thì (giả sử) người dùng có hack/cheat để vượt quá tầng front-end (ví dụ disable javascript), thì vẫn còn 1 chốt chặn ở server nữa.

Trong bài này, mình sẽ giới thiệu một số cách sử dụng validation cơ-bản-nhất trong asp.net mvc, sử dụng data annotation và 1 thư viện validate rất cool do 1 dev của Việt Nam tạo ra, đó là bootstrap validator.

bootstrap validator (bv) là tiền thân của formvalidation. Sự khác nhau là bv là 1 phiên bản miễn phí, chỉ sự dụng cho bootstrap. Phiên bản mới nhất hỗ trợ được nhiều css framework khác và tính phí. Trong bài này mình chỉ nói tới bootstrap validator.

UI

Xây dựng 1 layout đơn giản như sau:

form-validate

html

Model

Tạm thời model sẽ đơn giản thế này thôi.

1. Data Annotation

Hãy cùng xem và phân tích nhé:

Đầu tiên là namespace để sử dụng được các attributes:

using System.ComponentModel.DataAnnotations;

Với mỗi attribute sẽ có các thuộc tính (property) để validate. Ví dụ đối với RequiredAttribute của Name property:

[Required(ErrorMessage = "{0} is required")]

Tham số thứ 0 luôn luôn là tên của property, ở đây là Name. Nếu bạn muốn custom name khi hiển thị, bạn sử dụng kèm với DisplayAttribute bằng cách [Display(Name = "my custom name")].

Quay lại với RequiredAttribute ở trên, khi bạn submit mà chưa nhập tên, kết quả sinh ra sẽ là:

Product name is required

Dễ hiểu phải không! :))

Tiếp, ví dụ như validate số lượng ký tự nhập vào với [StringLength]

[StringLength(250, MinimumLength = 2, ErrorMessage = "{0} must be from {2} to {1} characters")]

  • 250: MaximumLength (default parameter) là 250 ký tự
  • MinimumLength = 2: tối thiểu 2 ký tự
  • ErrorMessage: lỗi khi nhập 1 ký tự hoặc vượt quá 250 ký tự. Nhìn vào đây sẽ hiểu được cách sử dụng parameters, {0} luôn là tên của property, {2} là tham số thứ 2 (min length), {1} là tham số đầu tiên.

Đơn giản mà, rất là gợi nhớ và đầy đủ ngữ nghĩa nên bạn không khó để sử dụng.

Tham khảo tại đây để xem các attribute hỗ trợ nhé.

Thêm 1 chút về cách viết annotation, bạn có thể viết tách ra như thế này:

hoặc gộp lại thành 1 như thế này:

bạn có thể viết cách nào mà bạn thấy thích nhất. (Mình thích cách tách ra, dễ nhìn và chỉnh sửa hơn)

Sử dụng validate attribute

Quay trở lại với html 1 chút, nếu bạn chưa biết thì:

@Html.TextBoxFor(m => m.Name, new { @class="form-control"})

là 1 Html helper, trong asp.net mvc (razor syntax) nó được sử dụng để sinh ra html.

Ví dụ như với helper ở trên, kết quả sinh ra sẽ là:

html-helper-generated

yes, cũng chỉ là 1 input bình thường, nhưng nó có gắn thêm name=Name (Name là tên của property, asp.net mvc model binder sẽ bind dựa vào name). Đây là 1 trong những lợi thế khi sử dụng html helper thay cho html tag bình thường.

À, nếu bạn chưa biết thì sự khác nhau giữa @Html.TextBox()@Html.TextBoxFor() đó là TextBoxFor sinh ra html có gắn với 1 property cụ thể (nào đó) và được auto-binding vào Action (bạn viết ra là sẽ hiểu). For = For something, ví dụ textbox cho cái Id, textbox cho cái Name...

Không những thế, khi sử dụng kết hợp với data annotation, html sinh ra sẽ có thêm nhiều attributes khác nữa. Với những attribute mình đã thêm ở trên thì kết quả sẽ là:

validation-rules

Nó là các html attributes có dạng data- (data- là custom attribute được sử dụng trong html5). Tới đây thì bạn vẫn chưa sử dụng được các validation rules này (thực ra là bạn có thể sử dụng, chỉ là bạn không thấy hiển thị nếu bị lỗi thôi), bạn phải thêm vào 1 helper nữa để validate, đó là:

2. Validation message

@Html.ValidationMessageFor(m => m.Name)

Tương tự như @Html.TextBoxFor, cái này sẽ sinh ra html để thông báo lỗi cho 1 property nếu như property đó phạm lỗi.

Thêm helper cho các property khác:

3. Action

Bước cuối cùng, trong action bạn kiểm tra model có hợp lệ hay không bằng ModelState

Bạn có thể select danh sách lỗi bằng 1 câu linq đơn giản:

Hoặc hiển thị tất cả các lỗi ra giao diện bằng cách thêm helper:

Kết quả:

error-messages

Việc hiển thị trên hay dưới, đỏ hay đen, ngang hay dọc thì bạn hoàn toàn có thể quyết định được bằng cách thay đổi html và css cho form nhé.

Ok, validate bằng data annotation cơ bản là thế, 1 số chú ý khác khi sử dụng là:

  • Nếu muốn sử dụng cho đa ngôn ngữ, bạn có thể tham khảo tại đây.
  • Nếu các build-in attribute chưa đủ làm bạn thỏa mãn, bạn có thể viết custom attribute, đơn giản thôi, xem tại đây.

Bootstrap validator (bv)

Link download ở phía trên nhé.

Thư viện bv được sử dụng đi kèm với bootstrap, do đó, hiển nhiên là bạn phải dùng bootstrap chứ không phải framework khác nhé.

Đầu tiên, thêm bv vào _Layout.cshtml

insert-bootstrap-validator

Setup:

1 setup cơ bản như sau:

Trong đó icons là các icons hiển thị tương ứng với trạng thái của control (hợp lệ/không hợp lệ..), và fields là các option tương ứng cho mỗi control (lấy theo tên).

Ví dụ:

<input type="text" name="MyName" />

thì option tương ứng sẽ là:

fields: { MyName: {} }

dễ hiểu phải không :).

Tiếp theo, để setup các rules cho 1 control, sử dụng validators:

Với rules như vậy, ví dụ bạn submit mà không nhập Name, thì rules notEmpty sẽ bị violate, và message Name is required sẽ hiển thị.

Bạn có thể download source code của bv về và xem các ví dụ demo để biết thêm các validators được sử dụng trong bv.

Kết quả:

bv-result

Dành cho người lười

Chắc chắn là cái website của bạn không chỉ có 1 form rồi, và mỗi lần setup bv cũng..khá tốn thời gian phải không. Vậy thì hãy thêm tí mắm muối để đỡ vất vả hơn nhé.

Phân tích html 1 chút sẽ thấy ngay, mọi html sinh ra bởi html helper của thuộc tính có sử dụng validate đều có 1 điểm chung:

input-data-val.png

yes, và các rule cũng được thêm theo quy tắc: data-val-[rule], ví dụ như:

<input type="text" data-val="true" data-val-required="Product name is required" />

Vậy thì mình sẽ build 1 đoạn script nhỏ để lấy tất cả các data-val-* attribute trong form, và từ đó build nên các validate rules:

với script build rule như sau:

2 đoạn js trên khá đơn giản (với những người biết js, nếu bạn chưa rành thì cứ tiếp tục xem cho rành nhé :v) nên mình không giải thích (giải thích dài dòng). Trên đây mình chỉ build cho các rules thường gặp nhất, nếu bạn muốn add thêm rule, cứ việc xem html generated ra và thêm vào thôi.

Vậy công việc của bạn bây giờ đơn giản hơn rất nhiều, gọi hàm formValidationBuilder():

form-validator-builder

and..done! Đơn giản phải không :))

Kết

Bootstrap validator rất dễ sử dụng và hiệu quả, tuy nhiên điểm yếu của nó là phụ thuộc vào bootstrap (có lẽ vì vậy mà tác giả mới nâng lên form validation). Nhưng không sao, đa số các back-end site vẫn hay dùng bootstrap mà :))

Ok, kết ngắn gọn: vào đây mà tải source code để nghiên cứu thêm nhé :)

Comments

  1. nếu một view của mình có 2 form mà mỗi form một model khác nhu thì làm sao vạy admin

    ReplyDelete
    Replies
    1. buildValidator("#form1");
      buildValidator("#form2");

      Đơn giản vậy thôi :)

      Delete
  2. Làm sao để mình validation trên modal vậy bạn ?

    ReplyDelete
    Replies
    1. hàm build validator nhận vào 1 selector để tìm kiếm các input elements phía trong nó, bạn muốn validate cái gì (kể cả modal) thì cứ build validator cho cái đó thôi.

      Trường hợp 1: bạn có modal tĩnh, việc build sẽ đơn giản (như thông thường).
      Trường hợp 2: bạn gọi modal từ partial view, cũng đơn giản không kém. Khi đó bạn có thể build validator lúc load xong partial, hoặc bỏ đoạn script build trong partial view luôn.

      Delete
    2. mình viết modal + validation cho hàm create, khi ấn submit là nó nhảy sang view create dạng partial luôn là sao ~~

      Delete
  3. cảm ơn tác giả vì bài viết, chi tiết và rành mạch :D

    ReplyDelete
  4. cho mình hỏi có cách nào sau khi return view báo lỗi các input trống thì những ô đã nhập vẫn giữ nguyên không bị xóa trống ko vậy ad ơi

    ReplyDelete
    Replies
    1. cái này tùy thuộc vào cách làm của bạn.

      - nếu bạn dùng ajax để submit, tất nhiên các field sẽ vẫn giữ giá trị cũ
      - nếu bạn submit form bình thường, và form của bạn bị invalid, khi return view thì bạn truyền model hiện tại vào là xong: return View(currentModel);

      Delete
  5. Bạn cho mình hỏi làm sao để sử dụng RequiredIf nhỉ?

    ReplyDelete

Post a Comment

Popular posts from this blog

Gỡ bộ Visual Studio ra khỏi máy tính

Căn giữa thẻ div trong thẻ div