Routing trong ASP.NET Core

Trong mô hình MVC, chúng ta có ba thành phần là Model - View - Controller, mỗi thành phần tập trung vào một công việc cụ thể.

Khi một yêu cầu HTTP được gửi tới ứng dụng ASP.NET Core, nó sẽ được chuyển đến controller phù hợp. Quá trình này được gọi là định tuyến (routing).

Bạn có thể truy cập Hướng dẫn lập trình ASP.NET Core để không bỏ lỡ bất kỳ bài viết nào của chúng tôi.

Định tuyến trong ASP.NET Core

Chúng ta có thể cấu hình định tuyến trong lớp Startup hoặc sử dụng các thuộc tính (attribute). Chúng mô tả cách chúng ta có thể khớp các đường dẫn URL với các phương thức hành động (action) trong controller. Chúng ta cũng có thể sử dụng cấu hình định tuyến để tạo URL cho các liên kết được gửi đi trong phản hồi.

ASP.NET Core hỗ trợ hai cách cấu hình định tuyến là:

  • Cấu hình routing thông thường.
  • Cấu hình routing sử dụng RouteAttribute.

Cấu hình định tuyến thông thường trong ASP.NET Core

Khi chúng ta tạo một ứng dụng ASP.NET Core MVC mới theo mẫu trong Visual Studio, ứng dụng đã được cấu hình định tuyến mặc định. Hãy tạo một dự án mới và kiểm tra điều này.

Sau khi tạo một dự án mới với mẫu ASP.NET Core MVC mặc định, chúng ta hãy xem lớp Startup.cs. Chúng ta có thể thấy rằng ứng dụng đã được cấu hình một định tuyến mặc định trong phương thức Configure():

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

Bên trong phương thức UseMvc(), chúng ta sử dụng phương thức MapRoute() để tạo định tuyến có tên là default. default được cấu hình mẫu định tuyến là {controller=Home}/{action=Index}/{id?}.

Như bạn đã thấy ở trên, mẫu định tuyến của default có 3 phần lần lượt là {controller=Home}, {action=Index}{id?} phân cách nhau bằng dấu /. Trong đó:

  • {controller=Home} là tên của controller, nếu không có trên URL thì sẽ sử dụng giá trị mặc định là HomeController.
  • {action=Index} là tên của phương thức hành động (action method) trong controller. Nếu không có trên URL thì sẽ sử dụng giá trị măc định là phương thức hành động Index.
  • id? là tham số truyền vào cho phương thức hành động. Dấu ? có ý nghĩa là id không bắt buộc.

Nếu bạn chạy chương trình, lúc này URL không có thông tin controller, actionid, nên nó sẽ sử dụng thông tin mặc định để truy cập tới phương thức hành động Index của controller HomeController.

Khi người dùng truy cập đường dẫn URL như /Books/Details/5 chẳng hạn, hệ thống sẽ trích xuất các giá trị định tuyến bằng cách phân tách đường dẫn như sau: { controller = Books, action = Details, id = 5 }. MVC sẽ truy cập tới controller BooksController và chạy phương thức hành động Details() bằng cách chuyển tham số id là 5.

Hãy chạy ứng dụng ở chế độ Debug và đặt một breakpoint trong phương thức hành động (action method) Index() của HomeController. Chúng ta có thể thấy rằng phương thức này được thực thi theo mặc định. Điều này là do chúng ta đã xác định những giá trị này là các giá trị mặc định trong định tuyến default.

Bây giờ chúng ta hãy thêm một controller mới tên là BooksController với một phương thức hành động Details() và một tham số tùy chọn id:

public class BooksController : Controller
{
    public IActionResult Details(int id)
    {
        ViewBag.Id = id;
        return View();
    }
}

Sau đó, hãy tạo view cho phương thức hành động Details() như sau:

@{
    ViewData["Title"] = "Details";
    int id = ViewBag.Id;
}

<h1>Details</h1>

Book Id : @id 

Cuối cùng, chúng ta thay đổi định tuyến mặc định trong lớp Startup như sau:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Books}/{action=Details}/{id?}");
});

Bây giờ hãy chạy ứng dụng một lần nữa. Chúng ta có thể thấy rằng ứng dụng sẽ gọi đến phương thức hành động Details() của BooksController theo mặc định:

Trong phần này, chúng tôi đã tìm hiểu cách thức định tuyến hoạt động và cách cấu hình tuyến mặc định cho ứng dụng. Bây giờ hãy xem cách cấu hình nhiều định tuyến.

Cấu hình nhiều định tuyến

Chúng ta có thể thêm nhiều định tuyến bên trong phương thức UseMvc() bằng cách gọi phương thức MapRoute() nhiều lần. Điều này cho phép chúng ta định nghĩa nhiều quy ước hoặc thêm các định tuyến dành riêng cho một hành động cụ thể:

app.UseMvc(routes =>
{
   routes.MapRoute("blog", "blog/{*article}",
            defaults: new { controller = "Blog", action = "Article" });

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

Định tuyến blog ở trên đây sử dụng hệ thống định tuyến thông thường nhưng được dành riêng cho một hành động cụ thể. Do đây là những định tuyến riêng cho một hành động cụ thể nên chúng ta luôn phải chỉ định rõ thông tin phương thức hành động, controller khi cấu hình.

Các định tuyến trong danh sách định tuyến được đặt theo thứ tự và sẽ được xử lý theo thứ tự chúng ta thêm chúng. Vì vậy, trong ví dụ này, MVC sẽ thử định tuyến blog trước định tuyến default.

Luôn luôn tốt khi chỉ định tên tuyến trong khi tạo tuyến. Nó cung cấp cho tuyến một tên logic để chúng ta có thể sử dụng tuyến được đặt tên để tạo URL.

Như vậy là chúng ta đã tìm hiểu cách cấu hình định tuyến thông thường. Tiếp theo, chúng ta sẽ tìm hiểu về định tuyến bằng thuộc tính.

Định tuyến bằng thuộc tính

Bằng cách đặt các thuộc tính định tuyến (RouteAttribute) trên controller hoặc phương thức hành động, chúng ta có thể sử dụng tính năng định tuyến bằng thuộc tính (attribute routing).

Hãy sửa đổi phương thức Configure() trong lớp Startup.cs bằng cách xóa các định tuyến mặc định mà chúng ta đã cấu hình trước đó.

app.UseMvc();

Cuối cùng, chúng ta sửa lại controller BooksController bằng cách sử dụng các RouteAttribute như sau:

public class BooksController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    public IActionResult Index()
    {
        return View();
    }

    [Route("Home/Details/{id:int}")]
    public IActionResult Details(int id)
    {
        ViewBag.Id = id;
        return View();
    }
}

Bây giờ chúng ta có thể truy cập phương thức hành động Index() bằng các đường dẫn URL: /, /Home hoặc /Home/Index và truy cập phương thức hành động Details() bằng đường dẫn URL /Home/Details/{id}.

Khi sử dụng định tuyến thuộc tính, tên của controller và tên phương thức hành động không đóng vai trò trong việc lựa chọn phương thức hành động nào sẽ được thực hiện.

Chúng ta cũng có thể sử dụng các thuộc tính Http[Verb] để định tuyến bằng thuộc tính:

[HttpGet("/books")]
public IActionResult ListBooks()
{
   // ...
}

[HttpPost("/books")]
public IActionResult CreateBook(...)
{
   // ...
}

Như bạn thấy ở ví dụ trên, cùng là một đường dẫn URL /books nhưng MVC sẽ thực thi phương thức hành động ListBooks() khi phương thức HTTP là GETCreateBook() khi phương thức HTTP là POST.

Các thuộc tính định tuyến được định nghĩa trên controller có thể kết hợp với các thuộc tính tuyến trên các phương thức hành động riêng lẻ để tạo thành URL hoàn chỉnh.

Bất kỳ mẫu định tuyến nào được định nghĩa trên controller đều được thêm vào các định tuyến trên tất cả các phương thức hành động của nó.

Khi chúng ta đặt một thuộc tính tuyến trên controller, tất cả các phương thức hành động trong controller đều sử dụng định tuyến thuộc tính.

Ngoài ra, các thuộc tính định tuyến cũng hỗ trợ các thẻ như: [action], [area][controller]. Các thẻ này sẽ được tự động thay thế bằng các giá trị của action name, area namecontroller name.

[Route("[controller]/[action]")]
public class BooksController : Controller
{
    [HttpGet]
    public IActionResult List() 
    {
        // ...
    }

    [HttpGet("{id}")]
    public IActionResult Edit(int id) 
    {
        // ...
    }
}

Phương thức hành động List() có thể truy cập bằng đường dẫn URL /Books/List và phương thức hành động Edit() có thể truy cập bằng đường dẫn URL /Books/Edit/{id}.

Trong phần này, chúng ta đã tìm hiểu cách cấu hình định tuyến bằng thuộc tính. Bây giờ hãy xem cách định nghĩa nhiều định tuyến bằng thuộc tính.

Cấu hình nhiều định tuyến bằng thuộc tính

Định tuyến thuộc tính hỗ trợ định nghĩa nhiều định tuyến cho cùng một hành động. Cách sử dụng phổ biến nhất của kiểu cấu hình này là để truy cập phương thức hành động Index() của controller. Hãy xem ví dụ sau:

[Route("[controller]")]
public class BooksController : Controller
{
   [Route("")]     // Matches 'Books'
   [Route("Index")] // Matches 'Books/Index'
   public IActionResult Index()
   {
       return View();
   }
}

Bằng cách định nghĩa hai định tuyến bằng thuộc tính RouteAttribute, phương thức hành động Index() có thể truy cập bằng đường dẫn URL /BooksBooks/Index.

Kết luận

Trong bài viết này, chúng ta đã học được các nội dung sau:

  • Tạo một mẫu định tuyến thông thường cho ứng dụng ASP.NET Core MVC.
  • Cấu hình định tuyến thuộc tính cho controller và phương thức hành động (action method).
  • Cầu hình nhiều định tuyến cho cả định tuyến thông thường và định tuyến thuộc tính.
ASP.NET Core MVC
Bài Viết Liên Quan:
ASP.NET Core vs Go: Hiệu suất HTTP của ai tốt hơn
Trung Nguyen 11/10/2020
ASP.NET Core vs Go: Hiệu suất HTTP của ai tốt hơn

Trong bài viết này, chúng tôi sẽ so sánh hiệu suất HTTP của ASP.NET Core và Go sử dụng mô hình kiến trúc MVC.

ASP.NET Core Dependency Injection: Best Practice, Mẹo và Thủ Thuật
Trung Nguyen 10/10/2020
ASP.NET Core Dependency Injection: Best Practice, Mẹo và Thủ Thuật

Trong bài viết này, tôi sẽ chia sẻ các best practice, mẹo và thủ thuật về việc sử dụng Dependency Injection (DI) trong ứng dụng ASP.NET Core.

View Layout, View Start, View Imports trong ASP.NET Core
Trung Nguyen 10/04/2020
View Layout, View Start, View Imports trong ASP.NET Core

View Layout, View Start, View Imports là gì? Lợi ích và các sử dụng View Layout, View Start, View Imports trong ASP.NET Core.

View trong ASP.NET Core
Trung Nguyen 10/04/2020
View trong ASP.NET Core

Tất tần tật về View, Razor View, Layout View, View Start, View Import, Tag Helpers trong ASP.NET Core MVC.