Nguon: Microsoft Learn · .NET 8.0
Hướng dẫn: Tạo Web API dựa trên Controller với 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ức | Endpoint | Mô tả |
|---|---|---|
| GET | /api/todoitems | Lấy tất cả to-do item |
| GET | /api/todoitems/{id} | Lấy một item theo ID |
| POST | /api/todoitems | Thê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 2022 với workload ASP.NET and web development
- .NET 9.0 hoặc .NET 10.0 SDK
Visual Studio Code
- Visual Studio Code
- C# Dev Kit cho Visual Studio Code
- .NET 9 SDK
Thiết lập dự án
Tạo dự án Web API
Visual Studio:
- File → New → Project
- Tìm kiếm "Web API"
- Chọn template ASP.NET Core Web API
- Đặt tên dự án là TodoApi
- Xác nhận Framework: .NET 9.0 hoặc .NET 10.0
- Tích: Enable OpenAPI support và Use 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
- Nhấp chuột phải vào thư mục
Controllers - Chọn Add → New Scaffolded Item
- Chọn API Controller with actions, using Entity Framework
- Model class: TodoItem (TodoApi.Models)
- Data context class: TodoContext (TodoApi.Models)
- 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)
- Khởi động ứng dụng:
dotnet run --launch-profile https - Điều hướng đến
https://localhost:<port>/swagger - Kiểm thử các endpoint sử dụng Swagger UI
Sử dụng Endpoints Explorer (Visual Studio)
- Mở View → Other Windows → Endpoints Explorer
- Nhấp chuột phải vào endpoint và chọn Generate request
- 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
- [ApiController] kích hoạt xác thực model tự động và các phản hồi lỗi tốt hơn
- ActionResult\<T> cung cấp kiểu trả về linh hoạt với các HTTP status code phù hợp
- Mẫu DTO ngăn over-posting và kiểm soát dữ liệu được expose
- In-memory database (cơ sở dữ liệu trong bộ nhớ) được dùng cho hướng dẫn này; thay thế bằng SQL Server/PostgreSQL cho production
- Dependency Injection (tiêm phụ thuộc) cung cấp database context cho controller
- Routing:
[Route("api/[controller]")]tạo endpoint/api/todoitems