VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
ASP.NET Core Web APINền tảng web
Bài 3/19
5 phút

Controller và routing

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Controller mẫu trả về thời tiết, còn cửa hàng cần API sản phẩm. Bài này hướng dẫn tự viết controller đầu tiên và xem ASP.NET Core chọn method nào của controller để chạy khi có request tới.

Khái niệm

🎮 Controller: class kế thừa ControllerBase, gom các action xử lý request cho cùng một tài nguyên.

⚡ Action: method public trong controller, mỗi action ứng với một cặp HTTP method và URL.

🗺️ Routing: cơ chế ASP.NET Core dựa vào HTTP method và URL của request để chọn action sẽ chạy.

🏷️ Attribute: nhãn đặt trong [ ] phía trên class, method hay property để framework đọc và xử lý theo, ví dụ [HttpGet].

Ví dụ

Tạo file Controllers/ProductsController.cs:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
    private static readonly List<Product> Products =
        new List<Product>
        {
            new Product
            {
                Id = 1, Name = "Pen",
                Price = 5000m
            },
            new Product
            {
                Id = 2, Name = "Notebook",
                Price = 12000m
            },
        };

    [HttpGet]
    public List<Product> GetAll() => Products;

    [HttpGet("{id}")]
    public Product? GetById(int id) =>
        Products.FirstOrDefault(p => p.Id == id);
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public decimal Price { get; set; }
}
  • using Microsoft.AspNetCore.Mvc; mở namespace chứa ControllerBase và các attribute, thiếu thì compiler báo không tìm thấy tên.
  • [Route("api/products")] đặt đường dẫn chung cho cả controller.
  • [HttpGet] nối GET /api/products tới GetAll.
  • [HttpGet("{id}")] nối GET /api/products/2 tới GetById. Phần {id} trong URL được gán vào tham số id.
  • [ApiController] bật các hành vi dành cho API, như tự trả lỗi 400 khi dữ liệu gửi lên sai.
  • Mỗi request tạo một object controller mới, nên list phải static (bài static của C# Core) để mọi request dùng chung.
  • Danh sách sản phẩm để tạm trong bộ nhớ. Chương 4 sẽ chuyển sang database.

Routing ghép route của controller với route của action để chọn action:

api/products api/products + {id} GET /api/products GetAll() GET /api/products/2 GetById(id = 2)
Request được nối tới action nào

Thử ngay

Chạy lại server, rồi gọi lần lượt:

curl -i http://localhost:5000/api/products
curl -i http://localhost:5000/api/products/2
curl -i http://localhost:5000/api/products/99

Đoán trước khi chạy: sản phẩm số 99 không có. Lần gọi cuối trả status code nào?

Xem kết quả
HTTP/1.1 200 OK
[{"id":1,"name":"Pen","price":5000},{"id":2,"name":"Notebook","price":12000}]

HTTP/1.1 200 OK
{"id":2,"name":"Notebook","price":12000}

HTTP/1.1 204 No Content

Không phải 404 mà là 204. Action trả về null, ASP.NET Core hiểu đó là "thành công nhưng không có dữ liệu". Bài Trả về kết quả sẽ hướng dẫn trả 404 đúng cách.

Lỗi hay gặp

Controller có [ApiController] nhưng thiếu [Route]. Mọi request đều nhận lỗi 500, log báo action phải có route.

// SAI — thiếu [Route], request nào cũng lỗi 500
using Microsoft.AspNetCore.Mvc;

[ApiController]
public class OrdersController : ControllerBase
{
    [HttpGet]
    public string GetAll() => "orders";
}
// ĐÚNG
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    [HttpGet]
    public string GetAll() => "orders";
}

Hai action cùng method và cùng URL. ASP.NET Core không biết chọn cái nào, nên request nhận lỗi 500.

// SAI — hai action đều là GET /api/customers
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/customers")]
public class CustomersController : ControllerBase
{
    [HttpGet]
    public string GetAll() => "all";

    [HttpGet]
    public string GetActive() => "active";
}

Sửa bằng cách cho action thứ hai một URL riêng.

// ĐÚNG — GET /api/customers/active
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/customers")]
public class CustomersController : ControllerBase
{
    [HttpGet]
    public string GetAll() => "all";

    [HttpGet("active")]
    public string GetActive() => "active";
}

Tóm tắt

  • Controller kế thừa ControllerBase, đánh dấu [ApiController] và [Route].
  • Mỗi action có [HttpGet], [HttpPost]… kèm phần URL riêng nếu cần.
  • {id} trong route được gán vào tham số cùng tên.
  • Action trả về null thì response là 204, không phải 404.

Tự kiểm tra

0/3 câu
Câu 1

Controller có [Route("api/orders")], action có [HttpGet("{id}/lines")]. URL nào gọi tới action này?

Câu 2

Action GetById(int id) trả về null khi không tìm thấy. Client nhận status code nào?

Câu 3

OrdersController có [ApiController], [Route("api/orders")] và một method private string Load() gắn [HttpGet]. Gọi GET /api/orders nhận gì?

Tạo Web API đầu tiênNhận dữ liệu từ request

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt