C# cơ bản .NET Core

HTML Form cơ bản trong ASP.NET Core

HTML FORM là phần tử quan trong của trang HTML, nó có chức năng nhận dữ liệu của người dùng sau đó dữ liệu được gửi tới ứng dụng (máy chủ web), trong Form có các phần tử HTML như <input>, <button>, <select> ... Kiến thức về Form HTML xem tại: Thẻ HTML FormForm với HTML5, dùng CSS Bootstrap để trình bày form xem tại Bootstrap Form

Trong phần hướng dẫn này sẽ tạo và sử dụng Form trong ASP.NET từ cơ bản đến phức tạp, từ mã HTML thuần túy đến sử dụng các TagHelper của ASP.NET ... Hãy nhanh chóng tạo ra một dự án ASP.NET Razor Pages để thực hành, tạo thư mục razor06.form và gõ lệnh:

dotnet new webapp

Tạo HTML Form đơn giản

Tạo ra file Pages/Form.cshtml với nội dung:

@page
@{
    ViewData["Title"] = "Thêm khách hàng"; 
}

<h2 class="display-4">Nhập thông tin</h2>
<form method="post" class="m-2 p-3 bg-light">
  <div class="form-group">
      <label for="customername">Tên khách hàng:</label>
      <input class="form-control" type="text" name="customername" value="" />
  </div>
  <div class="form-group">
      <label for="email">Địa chỉ email:</label>
      <input class="form-control" type="email" name="email" value="" />
  </div>
  <div class="form-group">
      <label for="yearofbirth">Năm sinh:</label>
      <input class="form-control" type="text" name="yearofbirth" value="" />
  </div>
  <div class="form-group">
      <input class="btn btn-danger" type="submit" value="Gửi dữ liệu" />
  </div>
</form>

Chạy thử (dotnet run) và truy cập địa chỉ: https://localhost:5001/Form

aspnetform

Đọc thông tin gửi đến từ Form

ASP.NET Core chứa các thông tin gửi đến trong một đối tượng HTTP Request. Đối tượng này có được bằng truy cập thuộc tính của Request của Controller, của PageModel (lớp sinh ra bởi Razor). Có thể nhúng code C# ngay trong .cshtml như sau (xem thêm chỉ thị trong Razor ):

Pages/Form.cshtml

  @page
  @using System;
  @{
      ViewData["Title"] = "Thêm khách hàng";

      @functions {

          dynamic customerinfo {set;  get;}

          public void OnPost() {

              string customername = Request.Form["customername"];
              string email = Request.Form["email"];
              int yearofbirth  = Convert.ToInt32(Request.Form["yearofbirth"]);

              customerinfo =
              new {
                  customername = customername,
                  email = email,
                  yearofbirth = yearofbirth
              };


          }
        }
  }


 @{
     if (customerinfo != null)
     {
        <h3>Thông tin gửi</h3>
        <div class="card">
            <div class="card-body">
                <p><strong>Tên: </strong> @customerinfo.customername</p>
                <p><strong>Email: </strong> @customerinfo.email</p>
                <p><strong>Năm sinh: </strong> @customerinfo.yearofbirth</p>
            </div>
        </div>
     }
 }  

  <h2 class="display-4">Nhập thông tin</h2>
  <form method="post" class="m-2 p-3 bg-light">
      <div class="form-group">
          <label for="customername">Tên khách hàng:</label>
          <input class="form-control" type="text" name="customername" value="" />
      </div>
      <div class="form-group">
          <label for="email">Địa chỉ email:</label>
          <input class="form-control" type="email" name="email" value="" />
      </div>
      <div class="form-group">
          <label for="yearofbirth">Năm sinh:</label>
          <input class="form-control" type="text" name="yearofbirth" value="" />
      </div>
      <div class="form-group">
          <input class="btn btn-danger" type="submit" value="Gửi dữ liệu" />
      </div>
  </form>

Kết quả đọc được dữ liệu Post đến từ Form

aspnetform

Validation kiểm tra dữ liệu gửi đến

Để đảm bảo dữ liệu chính xác, cần kiểm tra nó trước khi các xử lý tiếp theo. Để kiểm tra dữ liệu, ASP.NET Core hỗ trợ với khi sử dụng DataAnnotation Attribute với mô hình Model Binding ở bài trước. Các thuộc tính của các đối tượng Model có thể khai báo sử dụng các DataAnnotation Attribute như:

Attribute Sử dụng
Required Thuộc tính cần phải có giá trị
StringLength Chiều dài chuỗi (tối thiểu, tối đa)
Range Số nằm trong một khoảng nào đó
RegularExpression Giá trị phù hợp với biểu thức chính quy
CustomValidation Thuộc tính sử dụng Validation tự tạo
EmailAddress Là địa chỉ email
FileExtension Những phần mở rộng file phù hợp
MaxLength Dài tối đa của phần tử mảng, chuỗi
MinLength Dài tối thiểu
Phone Là số điện thoại

Áp dụng Validation dữ liệu gửi đến, ta sẽ dùng kỹ thuật Model Binding (xem bài trước Model Binding , xây dựng một lớp biểu diễn thông tin khách hàng gửi đến )

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

public class CustomerInfo {

    [Required(ErrorMessage="Phải có tên")]
    [StringLength(20, MinimumLength = 3, ErrorMessage="Chiều dài không chính xác")]
    [Display(Name = "TÊN KHÁCH")] // Label hiện thị
    public string Customername {set; get;}

    [Required]
    [EmailAddress]
    [Display(Name = "EMAIL")]
    public string Email {set; get;}

    [Required(ErrorMessage="Thiếu năm sinh")]
    [Display(Name ="NĂM SINH")]
    [Range(1970, 2000, ErrorMessage = "Khoảng năm sinh sai")]
    public int? YearOfBirth {set; get;}
}

Xây dựng lớp FormModel, tạo file Pages/Form.cshtml.cs với nội dung

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace razor06.form.Pages
{
    public class FormModel : PageModel
    {
        public string Mesage {set; get;}
        [BindProperty]
        public CustomerInfo customerInfo {set; get;}

        public void OnPost() {
            if (ModelState.IsValid) {
                Mesage = "Dữ liệu Post chính xác";
                // Xử lý, chuyển hướng ...
            }
            else {
                Mesage = "Lỗi dữ liệu";
            }
        }
    }
}

Khi dữ liệu gửi lên được Binding, nó được tự động kiểm tra phù hợp với khai báo DataAnnotation Attribute, kiểm tra bằng ModelState.IsValid

Trog file Form.cshtml sử lại, trong đó các thành phần của Form có sử dụng TagHelper

  @page
  @model FormModel
   @{
     var customerinfo = Model.customerInfo;

     if (customerinfo != null)
     {

        <h3>@Model.Mesage</h3>
        <div asp-validation-summary="All"></div>
        if (ModelState.IsValid) {
            <div class="card">
                <div class="card-body">
                    <p><strong>Tên: </strong> @customerinfo.Customername</p>
                    <p><strong>Email: </strong> @customerinfo.Email</p>
                    <p><strong>Năm sinh: </strong> @customerinfo.YearOfBirth</p>
                </div>
            </div>
        }

     }
 }  


  <h2 class="display-4">Nhập thông tin</h2>
  <form method="post" class="m-2 p-3 bg-light">
      <div class="form-group">
          <label asp-for="@customerinfo.Customername"></label>
          <input class="form-control" asp-for="@customerinfo.Customername" />
          <span asp-validation-for="@customerinfo.Customername" class="text-danger"></span>  
      </div>
      <div class="form-group">
          <label asp-for="@customerinfo.Email"></label>
          <input class="form-control" asp-for="@customerinfo.Email" />
          <span asp-validation-for="@customerinfo.Email" class="text-danger"></span>
      </div>
      <div class="form-group">
          <label asp-for="@customerinfo.YearOfBirth"></label>
          <input class="form-control" asp-for="@customerinfo.YearOfBirth" />
          <span asp-validation-for="@customerinfo.YearOfBirth" class="text-danger"></span>
      </div>
      <div class="form-group">
          <button class="btn btn-danger" asp-page="Form">Gửi thông tin</button>
      </div>
  </form>
aspnetform

Tạo Validation riêng

Việc tạo ra một thuộc tính có chức năng Validation khá đơn giản, chỉ việc kế thừa lớp ValidationAttribute và nạp chồng phương thức IsValid. Ví dụ, tạo ra một Validation đặt tên là MyValidation có chức năng kiểm tra số nhập vào phải là số chẵn

public class MyValidation: ValidationAttribute
{
    public MyValidation() {
        ErrorMessage = "Không phải số chẵn";
    }

    public override bool IsValid(object value) {
        if (value == null) return false;
        int number = Int32.Parse(value.ToString());
        bool chiahetcho2 = number % 2 == 0;
        return chiahetcho2;

    }
}

Nếu áp dụng vào thuộc tính YearOfBirth của model trên

public class CustomerInfo {

    //..

    [Required(ErrorMessage="Thiếu năm sinh")]
    [Display(Name ="NĂM SINH")]
    [Range(1970, 2000, ErrorMessage = "Khoảng năm sinh sai")]
    [MyValidation]
    public int? YearOfBirth {set; get;}
}

Khi chạy, nếu nhập năm sinh là số lẽ sẽ lỗi.

Tạo ModelBinder riêng

Trong phần Binding Model trong ASP.NET Core đã biết - có thể liên kết dữ liệu tự động từ gửi đến vào các thuộc tính của Model. Bạn hoàn toàn có thể xây dựng một cơ chế tùy biến quá trình binding, kiểm tra và filter dữ liệu (biến đổi dữ liệu) khi binding.

Để tạo da một cơ chế binding riêng, bạn cần tạo ra một lớp triển khai từ giao diện IModelBinder sau đó sử dụng thuộc tính [ModelBinder] để chỉ ra sẽ áp dụng cơ chế binding tùy chọn.

Ví dụ, tạo ra một lớp đặt tên MyCheckNameBinding, có chức năng binding dữ liệu chuỗi, có kiểm tra chuỗi dữ liệu đầu vào không được có chuỗi "xxx", dữ liệu được cắt bỏ khoảng trắng, được chuyển sang chữ in hoa khi gán vào thuộc tính. Lớp này xây dựng như sau:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;

namespace razor06.form.Binding {

    // Liên kết dữ liệu (binding) - chuỗi dữ liệu gửi đến
    // phải không có chữ xxx - dữ liệu được filter thành chữ IN HOA
    public class MyCheckNameBinding : IModelBinder {
        private readonly ILogger<MyCheckNameBinding> _logger;

        // Inject các dịch vụ nếu muốn ở khởi tạo
        public MyCheckNameBinding (ILogger<MyCheckNameBinding> logger) {
            _logger = logger;
        }
        public Task BindModelAsync (ModelBindingContext bindingContext) {

            if (bindingContext == null) {
                throw new ArgumentNullException (nameof (bindingContext));
            }

            // Lấy ModelName - tên thuộc tính binding
            string modelName = bindingContext.ModelName;

            // Lấy giá trị gửi đến
            ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue (modelName);

            // Không có giá trị gửi đến (không thiết lập giá trị cho thuộc  tính)
            if (valueProviderResult == ValueProviderResult.None) {
                return Task.CompletedTask;
            }

            // Thiết lập cho ModelState giá trị bindinng
            bindingContext.ModelState.SetModelValue (modelName, valueProviderResult);

            // Đọc giá trị đầu tiên gửi đêns
            string value = valueProviderResult.FirstValue;

            // Xử lý nếu chuỗi giá trị gửi đến null
            if (string.IsNullOrEmpty (value)) {
                return Task.CompletedTask;
            }

            var s = value.ToUpper();

            if (s.Contains ("XXX")) {
                // chứa ký tự không được phép, thiết lập báo lỗi (không binding)
                bindingContext.ModelState.TryAddModelError (
                    modelName, "Không được phép chứa xxx.");
                return Task.CompletedTask;

            }

            // Gán giá trị vào thuộc tính (có loại bỏ khoảng trắng)
            bindingContext.Result = ModelBindingResult.Success(s.Trim());

            return Task.CompletedTask;

        }
    }
}

Để áp dụng MyCheckNameBinding thì sử dụng thuộc tính ModelBinder với cú pháp như sau:

[ModelBinder(BinderType = typeof(MyCheckNameBinding))]

Ví dụ, áp dụng vào Customername của CustomerInfo

public class CustomerInfo {

    [Required(ErrorMessage="Phải có tên")]
    [StringLength(20, MinimumLength = 3, ErrorMessage="Chiều dài không chính xác")]
    [Display(Name = "TÊN KHÁCH")] // Label hiện thị
    [ModelBinder(BinderType = typeof(MyCheckNameBinding))]  // Khi binding dữ liệu sẽ chuyển in hoa, không chứa XXX
    public string Customername {set; get;}

    // ...
}
aspnetform

Mã nguồn: ASP_NET_CORE/razor06.form


Đăng ký nhận bài viết mới