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 APIHoàn thiện API
Bài 17/19
5 phút

Xử lý lỗi tập trung

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

Database mất kết nối, code ném exception mà không ai bắt, client chỉ nhận 500 không rõ lý do. Bọc try/catch vào từng action thì code lặp lại khắp nơi. Bài này bắt mọi lỗi không lường trước ở một chỗ, còn lỗi cụ thể xử lý được thì vẫn dùng try/catch như bài Exception.

Khái niệm

🛡️ Xử lý lỗi tập trung: bắt mọi exception chưa được xử lý ở một chỗ duy nhất trong pipeline, rồi trả về response lỗi thống nhất.

📄 ProblemDetails: định dạng JSON chuẩn để mô tả lỗi trong HTTP API, gồm các trường như title, status, detail.

Ví dụ

using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddProblemDetails();
builder.Services
    .AddExceptionHandler<AppExceptionHandler>();

var app = builder.Build();
app.UseExceptionHandler();
app.MapControllers();
app.Run();

public class AppExceptionHandler : IExceptionHandler
{
    private readonly ILogger<AppExceptionHandler>
        _logger;

    public AppExceptionHandler(
        ILogger<AppExceptionHandler> logger)
    {
        _logger = logger;
    }

    public async ValueTask<bool> TryHandleAsync(
        HttpContext context,
        Exception exception,
        CancellationToken ct)
    {
        _logger.LogError(
            exception, "Lỗi chưa được xử lý");

        context.Response.StatusCode = 500;
        await context.Response.WriteAsJsonAsync(
            new ProblemDetails
            {
                Status = 500,
                Title = "Something went wrong",
            },
            ct);
        return true;
    }
}
  • IExceptionHandler là interface để viết bộ xử lý lỗi. TryHandleAsync được gọi khi có exception chưa ai bắt. ValueTask<bool> dùng như Task<bool>.
  • Bộ xử lý ghi log đầy đủ exception cho team, còn client chỉ nhận một câu chung chung.
  • Trả true nghĩa là lỗi đã được xử lý xong.
  • AddExceptionHandler đăng ký bộ xử lý, UseExceptionHandler() thêm nó vào pipeline. UseExceptionHandler() là một middleware, đặt đầu pipeline để bọc các bước sau.
  • ct dùng để huỷ việc ghi response khi client ngắt kết nối, ở đây chỉ cần truyền tiếp.

Đường đi của một exception chưa ai bắt:

Action ném exception UseExceptionHandler() AppExceptionHandler.TryHandleAsync Log của server: message + stack trace Client: 500 + ProblemDetails
Exception đi tới bộ xử lý lỗi tập trung

Thử ngay

Thêm một action cố tình ném lỗi vào project:

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/test")]
public class TestController : ControllerBase
{
    [HttpGet("boom")]
    public string Boom() =>
        throw new InvalidOperationException(
            "Mất kết nối tới kho ở Hà Nội");
}

=> throw ... cho method ném exception ngay thay vì trả về giá trị. Chạy server rồi gọi curl -i http://localhost:5000/api/test/boom.

Đoán trước khi chạy: câu "Mất kết nối tới kho ở Hà Nội" có xuất hiện trong response mà client nhận không?

Xem kết quả
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{"title":"Something went wrong","status":500}

Không. Câu đó chỉ nằm trong log của server, kèm stack trace đầy đủ. Client chỉ thấy thông báo chung, không biết gì về cấu trúc bên trong hệ thống.

Lỗi hay gặp

Bọc try/catch vào từng action. Cùng một đoạn xử lý lỗi bị chép lại ở khắp nơi, sửa một chỗ dễ quên chỗ khác.

// SAI — mọi action đều lặp lại khối này
using Microsoft.AspNetCore.Mvc;

public class OrdersController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        try
        {
            return Ok(id);
        }
        catch (Exception)
        {
            return StatusCode(500);
        }
    }
}
// ĐÚNG — lỗi để bộ xử lý tập trung bắt
using Microsoft.AspNetCore.Mvc;

public class OrdersController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        return Ok(id);
    }
}

Trả thẳng exception.Message hay stack trace cho client. Thông báo lỗi có thể chứa tên bảng, đường dẫn file, chuỗi kết nối. Chỉ ghi chúng vào log.

Tóm tắt

  • Bắt mọi exception chưa xử lý ở một chỗ bằng IExceptionHandler.
  • Đăng ký bằng AddExceptionHandler, bật bằng UseExceptionHandler().
  • Ghi log đầy đủ cho team, trả ProblemDetails ngắn gọn cho client.
  • Không bọc try/catch vào từng action, không lộ chi tiết lỗi ra ngoài.

Tự kiểm tra

0/3 câu
Câu 1

App có AddExceptionHandler và UseExceptionHandler(). Handler đặt StatusCode = 503 rồi trả ProblemDetails. Một action ném exception không ai bắt. Client nhận gì?

Câu 2

Thông tin chi tiết của exception (message, stack trace) nên đi đâu?

Câu 3

TryHandleAsync trả về true có ý nghĩa gì?

Quan hệ một-nhiềuXác thực bằng JWT

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