Chuyển tới nội dung chính

12 bài viết được gắn thẻ "C#"

Ngôn ngữ C# ở mức thực dụng — async, bất biến, pattern matching và những cái bẫy hay gặp.

Xem tất cả thẻ

Phát triển hướng kiểm thử (TDD) trong vòng đời phát triển hướng AI (AI-DLC): tổng quan bằng chứng và đề xuất thực hành

· 35 phút để đọc
Nguyễn Huỳnh Minh Tiến
Fullstack Developer @ Utop.io
Tóm tắt

Tóm tắt. Phát triển hướng kiểm thử (Test-Driven Development, TDD) là kỹ thuật lặp ba bước: viết một kiểm thử thất bại (Red), viết lượng mã tối thiểu để kiểm thử đó đạt (Green), rồi tái cấu trúc mã trong khi giữ toàn bộ kiểm thử đạt (Refactor). Các nghiên cứu thực nghiệm trước kỷ nguyên AI cho kết quả không đồng nhất: nghiên cứu tình huống trên bốn đội công nghiệp ghi nhận mật độ lỗi giảm 40–90% với chi phí thời gian ban đầu tăng 15–35%, trong khi phân tích tổng hợp 27 nghiên cứu chỉ thấy cải thiện nhỏ về chất lượng. Trong vòng đời phát triển hướng AI (AI-Driven Development Life Cycle, AI-DLC), nơi mã nguồn ngày càng do mô hình ngôn ngữ lớn (LLM) sinh ra, kiểm thử có thêm một chức năng: đóng vai trò đặc tả thực thi được, qua đó làm rõ ý định và kiểm chứng đầu ra của AI. Các nghiên cứu về sinh mã dẫn dắt bởi kiểm thử từ 2023 đến 2026 cho thấy việc cung cấp kiểm thử cho LLM cải thiện kết quả trên các bộ chuẩn, và hướng mới nhất cho phép mô hình tự sinh rồi tinh chỉnh đồng thời cả kiểm thử lẫn mã. Tuy vậy, bằng chứng chủ yếu đến từ bài toán chuẩn quy mô nhỏ, và chất lượng của chính bộ kiểm thử đặt giới hạn cho mọi kết luận về tính đúng đắn. Chưa có đánh giá nào ở cấp toàn bộ vòng đời AI-DLC.

Từ khoá: TDD, AI-DLC, kiểm thử đơn vị, mô hình ngôn ngữ lớn, đặc tả thực thi được, tái cấu trúc.

MailKit trong .NET: gửi email SMTP và dựng HTML email template chạy đúng trên Outlook

· 16 phút để đọc
Nguyễn Huỳnh Minh Tiến
Fullstack Developer @ Utop.io
Tóm tắt

MailKit là thư viện mail mã nguồn mở cho .NET (giấy phép MIT, tác giả Jeffrey Stedfast), nói được cả SMTP, IMAP và POP3. Tài liệu chính thức của Microsoft về System.Net.Mail.SmtpClient khuyến nghị thẳng việc dùng MailKit thay thế. Phần khó của việc gửi email không nằm ở chỗ gọi SendAsync — nó nằm ở cái HTML bên trong: Outlook classic render bằng engine của Word nên không có flex hay grid, Gmail cắt thư dài quá 102KB, và một thư chỉ có HTML mà thiếu bản plain-text thì điểm spam tăng ngay.

Gửi được email và gửi được email hiển thị đúng là hai bài toán khác nhau. Bài này giải quyết cả hai: phần đầu là cơ chế MailKit, phần sau là những ràng buộc rất cũ kỹ của HTML email mà không đọc trước thì sẽ mất buổi chiều ngồi hỏi vì sao cái template đẹp trên Chrome lại vỡ tan trên Outlook.

Một dấu tiếng Việt làm chết lời gọi API: cf-ipcity, HttpClient và giới hạn ASCII

· 13 phút để đọc
Nguyễn Huỳnh Minh Tiến
Fullstack Developer @ Utop.io
Tóm tắt

Cloudflare tự chèn cf-ipcity vào request đi vào, và với khách ở Việt Nam thì giá trị là Hồ Chí Minh — có dấu, tức non-ASCII. Service .NET forward nguyên xi mọi header sang lời gọi đi ra, nên giá trị đó rơi vào HttpClient. Điều bất ngờ là Headers.Add không ném exception, TryAddWithoutValidation cũng trả về true; mọi thứ chỉ nổ ở SendAsync với HttpRequestException: Request headers must contain only ASCII characters, và không byte nào rời khỏi tiến trình. Lỗi không nằm ở Cloudflare cũng không nằm ở .NET, mà ở chỗ ứng dụng forward mọi header vô điều kiện.

Bối cảnh là một nền tảng loyalty thương mại điện tử, quy mô khoảng ba triệu khách hàng. Tôi ẩn tên khách và mọi chi tiết định danh; phần kể được là phần kỹ thuật.

Mọi thứ nhìn đều bình thường. API đang chạy. Pod trên Kubernetes healthy. Database ổn. Request vào tới ứng dụng. Nhưng một lời gọi HTTP sang service nội bộ cứ hỏng trên production — và chỉ trên production.

Thứ làm nó hỏng, hoá ra, là tên thành phố của chính người dùng.

Forward header trong ASP.NET Core: vì sao 'forward hết' là một lỗi kiến trúc

· 14 phút để đọc
Nguyễn Huỳnh Minh Tiến
Fullstack Developer @ Utop.io
Tóm tắt

Vòng lặp copy mọi header từ request đi vào sang request đi ra là một anti-pattern, và nó hỏng theo ba hướng khác nhau: sai về tính đúng đắn (một giá trị non-ASCII làm HttpClient ném exception), sai về bảo mật (bạn tin và chuyển tiếp dữ liệu do client tự đặt), và sai về kiến trúc (header do hạ tầng chèn trở thành một phần hợp đồng của ứng dụng). Cách sửa là allowlist — khai tường minh danh sách header được phép đi qua — đặt trong một DelegatingHandler dùng chung. Khi viết handler đó, cẩn thận một cái bẫy: nó không sống trong scope của request.

Bài này khép lại cụm ba bài bắt đầu từ một sự cố production trên nền tảng loyalty khoảng ba triệu khách hàng, nơi header cf-ipcity: Hồ Chí Minh do Cloudflare chèn làm hỏng một lời gọi nội bộ. Bài đầu kể sự cố, bài hai giải thích vì sao header không mang được tiếng Việt. Bài này trả lời câu hỏi còn lại: viết lại chỗ đó thế nào cho đúng.

HTTP header có chứa được tiếng Việt không? ASCII, obs-text và chỗ .NET vạch ranh giới

· 13 phút để đọc
Nguyễn Huỳnh Minh Tiến
Fullstack Developer @ Utop.io
Tóm tắt

Trả lời ngắn: không, nếu bạn muốn nó đi qua mọi tầng an toàn. Đặc tả HTTP định nghĩa giá trị header bằng ký tự ASCII in được, cộng thêm một nhánh lỗi thời tên là obs-text cho phép byte 0x80–0xFF nhưng không quy định bảng mã nào để diễn giải chúng. Hệ quả là một chuỗi tiếng Việt có thể đi lọt một phần: í nằm trong Latin-1 nên biểu diễn được, còn ồ thì không, vì nó là U+1ED3 — vượt ngoài 0xFF. .NET chọn cách dứt khoát: HttpClient từ chối gửi mọi giá trị header non-ASCII. Muốn mang dữ liệu có dấu thì phải mã hoá, bằng percent-encoding, RFC 8187 hoặc Base64.

Bài này tách ra từ một sự cố production, nơi header cf-ipcity: Hồ Chí Minh do Cloudflare chèn làm HttpClient ném exception. Ở đó tôi dừng lại ở hiện tượng. Ở đây tôi trả lời câu hỏi mà hiện tượng ấy đặt ra: rốt cuộc HTTP header được phép chứa những gì?