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:
- Thêm trực tiếp vào URL Parameter
- 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}" và "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/)