Route Constrains trong ASP.NET Core

Route Constrains giúp chúng ta lọc và giới hạn các giá trị không mong muốn truyền vào controller action. Nó được kiểm tra bởi các ràng buộc áp dụng cho giá trị truyền vào URL Parameter. Ví dụ bạn muốn Route Engine của mình kiểm tra chính xác giá trị id truyền vào tham số id là kiểu số thay vì kiểu khác.

Route Constrains làm việc như thế nào?

Có 2 cách để bạn thêm Constrain vào URL Parameter:

  1. Thêm trực tiếp vào URL Parameter
  2. Sử dụng tham số Constrain trong phương thức MapRoute.

Inline Constraint được thêm vào URL Parameter sau dấu hai chấm (:):

routes.MapRoute("default", "{controller=Home}/{action=Index}/{id:int}");

Một khi Routeing Engine tìm thấy một Route đúng với URL, nó sẽ gọi Route Constraint để kiểm tra mỗi thành phần của URL xem có thỏa mãn không? Các constraint (ràng buộc) này chỉ đơn giản là trả về kết quả có thỏa mãn hay không. Nếu không có nghĩa là tham số không được chấp nhận.

Route Constraints

Mở project ra, cái mà bạn đã tạo trong bài Routing. Vào phương thức Configure và dùng đoạn code dưới đây:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseMvc(routes =>
    {
        routes.MapRoute("default",
                        "{controller}/{action}/{id?)}",
                        new { controller = "Home", action = "Index" });
    });
}

Giờ hãy copy đoạn code dưới đây vào method Index trong HomeController:

public class HomeController : Controller
{
    public string Index(int id)
    {
        return "I got " + id.ToString();
    }
}

Sau khi Request với URL là "/Home/Index/10" được tìm thấy trong route. Giá trị 10 sẽ được truyền vào như một tham số đến action method Index và bạn thấy dòng chữ "I got 10" trên trình duyệt.

Một request khác có URL "/Home/Index/Test" cũng đúng với route. Router thử chuyển giá trị "Test" sang giá trị 0 và truyền vào nó như một tham số đến Index action. Bạn sẽ nhận được dòng chữ "I got 0" trên trình duyệt.

Bạn có thể tránh điều này bằng cách sử dụng Route Constraint với tham số id.

Inline Constraint

Inline Constraint được thêm vào sau URL Parameter và được tách với dấu hai chấm. Ví dụ bạn có thể đảm bảo chỉ các giá trị số nguyên được chấp nhận:

routes.MapRoute("default", "{controller=Home}/{action=Index}/{id:int?}");

Ràng buộc int kiểm tra xem các giá trị của Id phải chuyển được sang số nguyên. Thành phần id là tùy chọn không bắt buộc . Vì thế route sẽ match nếu như Id không được chỉ ra, nhưng nếu một khi nó được chỉ ra thì nó phải là một giá trị số nguyên. Với int constraint thì Request "/Home/Index/Test" sẽ không match với route.

Sử dụng phương thức Constraint của MapRoute

Các constraints cũng được chỉ ra sử dụng các tham số constraints trong phương thức MapRoute. Để làm điều này bạn cần thêm namespace: Microsoft.AspNetCore.Routing.Constraints.

using Microsoft.AspNetCore.Routing.Constraints;
 
app.UseMvc(routes =>
{
    routes.MapRoute("default",
                    "{controller}/{action}/{id}",
                     new { controller = "Home", action = "Index" },
                     new { id = new IntRouteConstraint() });
});

Chúng ta tạo một thể hiện của kiểu Anonymous, nó chứa các thuộc tính có tên giống như URL Parameter và các ràng buộc được áp dụng. Các thuộc tính này được gán cho thể hiện của class Constraint.

Trong ví dụ trên chúng ta tạo một class nặc danh. Nó có thuộc tính id, match với id trong URL Parameter. Thể hiện của IntRouteConstraint được gán cho thuộc tính id.

Constraints trong Attribute Routing

Bạn cũng có thể đạt được điều này khi sử dụng Attribute routing:

[Route("Home/Index/{id:int}")]
public string Index(int id)
{
    return "I got " + id.ToString();
}

Sử dụng Constraints ở đâu?

Constrains được sử dụng cho việc kiểm tra đầu vào nhưng đó không phải là lý do nó tồn tại. Kiểm tra đầu vào (input validation) không phải được xử lý bởi Route Constraints. Thay vào đó Controller phải kiểm tra đầu vào và gửi thông báo lỗi tương ứng cho người dùng. Nếu bạn sử dụng Route Constraints để kiểm tra dữ liệu đầu vào thì người dùng sẽ nhìn thấy lỗi 404 (Not Found).

Route constraints nên được sử dụng để hỗ trợ Route Engine phân biệt giữa 2 route tương tự. Ví dụ:

app.UseMvc(routes =>
    {
        routes.MapRoute("default",
                        "post/{id:int}",
                        new { controller = "Post", action = "PostsByID" });
 
        routes.MapRoute("anotherRoute",
                        "post/{id:alpha}",
                        new { controller = "Post", action = "PostsByPostName" });
 
    });

Chúng ta có 2 Route nhìn giống nhau về pattern. Vì chúng đều là "post/{id:int}""post/{id:alpha}". Với hai kiểu dữ liệu là int và alpha (chỉ chấp nhận chữ cái), chúng ta có thể chỉ  cho Routing Engine chọn PostByID Ation method nếu giá trị là số và PostByPostName nếu giá trị id là kiểu chữ cái.

Danh sách của Route Constraint

Namespace Microsoft.AspNetCore.Routing.Constraints định nghĩa một tập các class có thể sử dụng để định nghĩa các constraint riêng lẻ.

Constraints để kiểm tra kiểu dữ liệu

Đây là các constraints để kiểm tra kiểu dữ liệu:

CONSTRAINT Cú pháp CLASS Ghi chú
int {id:int} IntRouteConstraint Kiểm tra tham số chỉ được là số nguyên 32 bit.
alpha {id:alpha} AlphaRouteConstraint Kiểm tra tham số chỉ được là ký tự thuộc bảng chữ cái tiếng anh A-Z
bool {id:bool} BoolRouteConstraint Kiểm tra tham số chỉ được là giá trị logic true hoặc false.
datetime {id:datetime} DateTimeRouteConstraint Kiểm tra tham số chỉ được là giá trị DateTime
decimal {id:decimal} DecimalRouteConstraint Kiểm tra giá trị tham số chỉ được là kiểu thập phân
double {id:double} DoubleRouteConstraint Cho phép giá trị tham số chỉ được là kiểu số thực 64 bit
float {id:float} FloatRouteConstraint Cho phép tham số chỉ là kiểu số thực dấu chấm động
guid {id:guid} GuidRouteConstraint Chỉ cho phép kiểu Guid

Constraints để kiểm tra giá trị/ miền giá trị và độ dài:

 

CONSTRAINT Cú pháp CLASS Ghi chú
length(length) {id:length(12)} LengthRouteConstraint Cho phép giá trị có độ dài trong khoảng
maxlength(value) {id:maxlength(8)} MaxLengthRouteConstraint Cho phép giá trị có độ dài tối đa nằm trong dấu ngoặc đơn.
minlength(value) {id:minlength(4)} MinLengthRouteConstraint Cho phép giá trị có độ dài tối thiểu nằm trong dấu ngoặc đơn.
range(min,max) {id:range(18,120)} RangeRouteConstraint Cho phép giá trị nằm trong khoảng
min(value) {id:min(18)} MinRouteConstraint Cho phép giá trị phải lớn hơn hoặc bằng giá trị trong ngoặc
max(value) {id:max(120)} MaxRouteConstraint Cho phép giá trị phải nhỏhơn hoặc bằng giá trị trong ngoặc

 Constraints kiểm tra sử dụng Regular Expression

CONSTRAINT Cú pháp CLASS Ghi chú
regex(expression) {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} RegexRouteConstraint Chứa giá trị thỏa mãn regular expression.

Ví dụ về Regular Express Route Constraint

Trong ví dụ dưới đây, chúng ta sử dụng biểu thức chính quy để hạn chế giá trị Year chỉ có 4 số:

app.UseMvc(routes =>
   {
   routes.MapRoute("default",
        "{controller}/{action}/{year:regex(^\\d{{4}}$)}",
        new { controller = "Home", action = "Index" });
});

Cập nhật Index method của HomeController.cs:

public class HomeController : Controller
{
    public string Index(int year)
    {
        return "Year = " + year.ToString();
     }
}

Một request với URL "Home/Index/2017" sẽ match với route nhưng "/Home/Index/20" thì không. Chú ý là biểu thức chính quy phải được thoát. Ví dụ: \,{,},[,] cần được đặt nó gấp đôi lên để thoát tránh lỗi cho parameter.

Vì thế ^\d{4}$ trở thành ^\\d{{4}}$.

Kết hợp các constraints

Nhiều constrains có thể được kết hợp bởi dấu hai chấm chia tách:

"/{id:alpha:minlength(6)?}"

Hoặc sử dụng phương thức Constraints trong MapRoute:

Using Microsoft.AspNetCore.Routing.CompositeRouteConstraint;
 
constraints: new {
    id = new CompositeRouteConstraint(
    new IRouteConstraint[] {
    new AlphaRouteConstraint(),
    new MinLengthRouteConstraint(6)
})

Tổng kết

Route Constraints rất hữu dụng trong việc phân biệt giữa các route giống nhau về URL Pattern. Nó giúp chúng ta giới hạn các giá trị không mong muốn truyền đến controller action.


Trích nguồn từ: (https://www.tektutorialshub.com/)

Lên trên