Nguon: Microsoft Learn · .NET 8.0

Hướng dẫn: Tạo Web API dựa trên Controller với ASP.NET Core

Nguồn: Tutorial: Create a web API with ASP.NET Core

Tổng quan

Hướng dẫn này dạy cách xây dựng web API dựa trên controller sử dụng database. Hướng dẫn tạo Todo Items API với các endpoint sau:

Phương thứcEndpointMô tả
GET/api/todoitemsLấy tất cả to-do item
GET/api/todoitems/{id}Lấy một item theo ID
POST/api/todoitemsThêm item mới
PUT/api/todoitems/{id}Cập nhật item hiện có
DELETE/api/todoitems/{id}Xóa một item

Điều kiện tiên quyết

Visual Studio

Visual Studio Code

Thiết lập dự án

Tạo dự án Web API

Visual Studio:

  1. File → New → Project
  2. Tìm kiếm "Web API"
  3. Chọn template ASP.NET Core Web API
  4. Đặt tên dự án là TodoApi
  5. Xác nhận Framework: .NET 9.0 hoặc .NET 10.0
  6. Tích: Enable OpenAPI supportUse controllers

Visual Studio Code:

bash
dotnet new webapi --use-controllers -o TodoApi
cd TodoApi
dotnet add package Microsoft.EntityFrameworkCore.InMemory
code -r .

Thêm package NuGet

bash
dotnet add package Microsoft.EntityFrameworkCore.InMemory

Các lớp Model

Model TodoItem

Tạo file Models/TodoItem.cs:

csharp
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Database Context (Ngữ cảnh cơ sở dữ liệu)

Tạo file Models/TodoContext.cs:

csharp
using Microsoft.EntityFrameworkCore;

namespace TodoApi.Models;

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

Cấu hình

Cập nhật Program.cs:

csharp
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.UseSwaggerUi(options =>
    {
        options.DocumentPath = "/openapi/v1.json";
    });
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

Scaffold Controller (Tạo nhanh Controller)

Visual Studio

  1. Nhấp chuột phải vào thư mục Controllers
  2. Chọn AddNew Scaffolded Item
  3. Chọn API Controller with actions, using Entity Framework
  4. Model class: TodoItem (TodoApi.Models)
  5. Data context class: TodoContext (TodoApi.Models)
  6. Chọn Add

Visual Studio Code

bash
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet aspnet-codegenerator controller -name TodoItemsController -async -api -m TodoItem -dc TodoContext -outDir Controllers

Các phương thức Controller đã được tạo

POST - Tạo item

csharp
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

Trả về HTTP 201 Created với header Location.

GET - Lấy item

csharp
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

PUT - Cập nhật item

csharp
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

Trả về HTTP 204 No Content.

DELETE - Xóa item

csharp
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

Trả về HTTP 204 No Content.

Data Transfer Objects (DTO — Đối tượng truyền dữ liệu)

Để ngăn over-posting (gửi dữ liệu thừa) và ẩn dữ liệu nhạy cảm, tạo DTO:

csharp
namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Cập nhật các phương thức controller để sử dụng DTO:

csharp
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
    return await _context.TodoItems
        .Select(x => ItemToDTO(x))
        .ToListAsync();
}

[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
    var todoItem = new TodoItem
    {
        IsComplete = todoDTO.IsComplete,
        Name = todoDTO.Name
    };

    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    return CreatedAtAction(
        nameof(GetTodoItem),
        new { id = todoItem.Id },
        ItemToDTO(todoItem));
}

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
    if (id != todoDTO.Id)
    {
        return BadRequest();
    }

    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    todoItem.Name = todoDTO.Name;
    todoItem.IsComplete = todoDTO.IsComplete;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
    {
        return NotFound();
    }

    return NoContent();
}

private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
   new TodoItemDTO
   {
       Id = todoItem.Id,
       Name = todoItem.Name,
       IsComplete = todoItem.IsComplete
   };

Kiểm thử API

Sử dụng Swagger UI (Visual Studio Code)

  1. Khởi động ứng dụng: dotnet run --launch-profile https
  2. Điều hướng đến https://localhost:<port>/swagger
  3. Kiểm thử các endpoint sử dụng Swagger UI

Sử dụng Endpoints Explorer (Visual Studio)

  1. Mở ViewOther WindowsEndpoints Explorer
  2. Nhấp chuột phải vào endpoint và chọn Generate request
  3. Xem phản hồi trong ngăn Response

Ví dụ kiểm thử - POST Request

json
{
  "name": "walk dog",
  "isComplete": true
}

Phản hồi:

json
{
  "id": 1,
  "name": "walk dog",
  "isComplete": true
}

Các điểm quan trọng

Tài nguyên bổ sung