6.13 — Review and Assessment
Mục tiêu bài học
- Nắm được ý chính của bài và mối liên hệ với module.
- Áp dụng được kiến thức vào bối cảnh CRM/.NET backend.
- Sẵn sàng chuyển sang bài kế tiếp với nền tảng chắc chắn.
Nội dung bài học
6.13.1 — Thực hành
Bài 1: Convert sync service thành async với CancellationToken
Cho sync service sau, hãy refactor thành async và pass CancellationToken xuyên suốt:
// TRƯỚC — sync, block thread
public class CustomerSyncService
{
private readonly AppDbContext _db;
public Customer? GetById(int id)
=> _db.Customers.FirstOrDefault(c => c.Id == id);
public List<Customer> GetAll()
=> _db.Customers.Where(c => c.IsActive).ToList();
public void UpdateLastContact(int id, DateTime contactDate)
{
var customer = _db.Customers.Find(id);
if (customer is null) return;
customer.LastContactDate = contactDate;
_db.SaveChanges();
}
}
Yêu cầu:
- Đổi tất cả method sang
async Task<T> - Dùng
FirstOrDefaultAsync,ToListAsync,FindAsync,SaveChangesAsync - Thêm
CancellationToken ct = defaultvào mỗi method - Viết unit test mock
DbContextđể kiểm tra cancel behavior
Bài 2: Gọi song song 3 service với WhenAll + timeout
// Implement method này
public class CustomerDashboardService
{
// Inject: IEmailNotifier, ISmsNotifier, IPushNotifier
/// <summary>
/// Gửi thông báo qua cả 3 kênh song song.
/// Nếu sau 5 giây chưa xong → cancel tất cả.
/// Thu thập lỗi từ từng kênh, log, không throw.
/// Trả về số kênh gửi thành công.
/// </summary>
public Task<int> SendToAllChannelsAsync(
int customerId,
string message,
CancellationToken ct = default)
{
throw new NotImplementedException(); // Implement đây
}
}
Yêu c ầu:
- Dùng
Task.WhenAllchạy 3 service song song - Áp dụng timeout 5 giây bằng
CancellationTokenSource.CreateLinkedTokenSource - Bắt lỗi từng task riêng lẻ, log, không fail toàn bộ
- Trả về số lượng kênh gửi thành công
Bài 3: IAsyncEnumerable<T> stream danh sách khách hàng
// Implement streaming export không load toàn bộ vào RAM
public class CustomerExportService
{
private readonly AppDbContext _db;
/// <summary>
/// Stream khách hàng từ DB, lọc theo criteria.
/// Caller tự quyết định làm gì với từng record (CSV, JSON, API push...).
/// </summary>
public IAsyncEnumerable<CustomerExportDto> StreamAsync(
CustomerExportCriteria criteria,
CancellationToken ct = default)
{
throw new NotImplementedException();
}
/// <summary>
/// Dùng StreamAsync để xuất ra file CSV từng dòng.
/// </summary>
public Task ExportToCsvAsync(string filePath, CustomerExportCriteria criteria, CancellationToken ct)
{
throw new NotImplementedException();
}
}
public record CustomerExportDto(int Id, string Name, string Email, DateTime CreatedAt);
public record CustomerExportCriteria(DateTime? FromDate, DateTime? ToDate, bool OnlyActive);
Yêu cầu:
- Dùng
EF Core AsAsyncEnumerable()+yield return - Áp dụng filter từ
criteria ExportToCsvAsyncdùngawait foreachđể ghi từng dòng- Đảm bảo
CancellationTokenđược truyền và tôn trọng
6.13.2 — Tóm tắt + Quick Reference
6.13.3 — Bảng Do / Don't
| Tình huống | DO ✅ | DON'T ❌ |
|---|---|---|
| Gọi DB / HTTP | await dbContext.X.ToListAsync(ct) | .ToList() trực tiếp |
| Chờ nhiều tasks độc lập | await Task.WhenAll(t1, t2, t3) | await t1; await t2; await t3; |
| Long-running operation | Pass CancellationToken xuyên suốt | Bỏ qua cancel |
| Library code | ConfigureAwait(false) | Không dùng ở app layer |
| Cần kết quả sync | Refactor caller thành async | .Result / .Wait() |
| Fire-and-forget | Bắt exception bên trong task | _ = DoAsync() không handle lỗi |
| Dataset lớn | IAsyncEnumerable<T> stream | Load toàn bộ vào List<T> |
| CPU-bound background | await Task.Run(...) | async Task trực tiếp |
| Event handler | async void + try/catch | async void không try/catch |
| Cache hot-path | ValueTask<T> | Task<T> mặc định cho mọi thứ |
6.13.4 — Checklist code review
- Mọi
asyncmethod đều cóawaitbên trong -
CancellationTokenđược truyền từ controller xuống repository - Không có
.Resulthoặc.Wait()trừ trongMainhoặc test -
Task.WhenAllđược dùng thay vìawaittuần tự cho tasks độc lập -
async voidchỉ xuất hiện trong event handler - Exception trong fire-and-forget được log
6.13.5 — Checklist trước khi sang bài tiếp theo
- Bạn đã nắm được các khái niệm chính và giải thích lại được bằng ví dụ của riêng mình.
- Bạn đã chạy hoặc mô phỏng ít nhất một ví dụ trong bài.
- Bạn đã hoàn thành phần quiz/lab cơ bản (hoặc ít nhất tự làm lại theo trí nhớ).
- Bạn đã ghi lại 3 ý chính: học được gì, còn vướng gì, sẽ áp dụng ở đâu trong CRM.
6.13.6 — Kiểm tra & Thực hành (100 điểm)
6.13.7 — Bối cảnh giáo trình (mục tiêu xuyên suốt)
Trục CRM — một mục tiêu rõ: bạn hướng tới CRM production trong From Zero → Senior .NET (Backend-first). Giáo trình ưu tiên backend, bám chuỗi API → dữ liệu → vận hành → kiến trúc phân tán, thay vì trải rộng theo hướng full-stack. Mỗi module củng cố một lớp kỹ năng trên cùng một CRM học tập bạn phát triển xuyên suốt khóa.
| Chuỗi năng lực | Đóng góp vào CRM học tập |
|---|---|
| Giai đoạn 1 — Foundation | Đọc hiểu yêu cầu, mô hình client–server, Git — nền collaboration khi CRM lớn dần. |
| Giai đoạn 2 — C# + P1 | Domain, OOP, LINQ, async, DI — rule nghiệp vụ & tầng ứng dụng (Inventory là bản mẫu trước CRM). |
| Giai đoạn 3 — ASP.NET + P2 | Host, routing, validation, JWT, SignalR — CRM Backend API thực tế. |
| Giai đoạn 4 — Data + P3 | SQL, EF, cache, job, container — CRM ổn định & có thể triển khai. |
| Giai đoạn 5 — Senior + Final | Clean Architecture, event/outbox, gateway, observability, perf — CRM/ERP chịu tải & có chủ. |
6.13.7.1 — Vai trò giai đoạn này trong chuỗi
C# professional + Project 1 (Inventory): OOP, LINQ, async, DI — domain & rule nghiệp vụ giống tầng lõi CRM/ERP.
6.13.7.2 — Vị trí bài học (trước / sau)
| Mốc | Điểm nối trong giáo trình |
|---|---|
| Trước | Module 5 — Advanced C# |
| Tiếp theo | Module 7 — Dependency Injection |
6.13.8 — Quy trình làm bài (hệ thống)
| Bước | Việc cần làm | Output nên có |
|---|---|---|
| 1 | Làm Quiz trước, tự ghi đáp án + 1 dòng lý do | Không xem đáp án; giữ bản nháp |
| 2 | Đối chiếu Đáp án; sửa hiểu sai, ghi takeaway vào README hoặc nhật ký học | 3–5 bullet “tôi đã hiểu…” |
| 3 | Làm Lab theo rubric; trong README nêu phần CRM nào được chạm (Lead, Customer, Deal, Billing…) | Repo / zip + ảnh dotnet run hoặc log |
| 4 | Tự chấm theo bảng điểm; chuẩn bị 1 phút “vấn đáp” nếu mentor hỏi ngẫu nhiên | Điểm + chỗ còn yếu |
6.13.9 — Phần A — Quiz trắc nghiệm (20 điểm)
Gợi ý làm bài: mỗi câu 4 điểm. Ưu tiên suy nghĩ hệ quả trên CRM (tiền, dữ liệu, đa tenant, hiệu năng, bảo mật) — không chỉ nhớ định nghĩa.
Mỗi câu 4 điểm.
-
async Taskmethod nên trả về gì khi không có giá trị?
A.voidB.TaskC.intD.ThreadĐáp án: B.
-
ConfigureAwait(false)chủ yếu quan tâm?
A. Tăng độ phân giải màn hình B. Không capture sync context (thư viện) C. Tắt exception D. Bắt buộc trên ASP.NET Core controllerĐáp án: B — trong app model ASP.NET Core thường ít cần; thư viện hay dùng.
-
Deadlock điển hình khi mix sync/async?
A.awaittronglockB..Result/.Wait()chặn context đang chờ continuation C. DùngTask.Runquá ít D.GC.Collect()Đáp án: B (mô hình phổ biến).
-
CancellationTokennên được?
A. Bỏ qua trong API public B. Truyền xuống call stack async C. Chỉ dùng trongMainD. Thay thế try/catchĐáp án: B.
-
async voidnên tránh ngoại trừ?
A. Repository method B. Event handler UI / top-level fire-and-forget có chủ đích C. Controller action D. Library public APIĐáp án: B.
6.13.10 — Phần B — Lab thực tế (80 điểm)
Lab & rubric: trong README, map từng nhóm điểm rubric sang phần CRM (Lead, Customer, Deal, Billing, Notification…) và artifact (test, log, screenshot, migration).
| Tiêu chí | Điểm | Ghi chú |
|---|---|---|
3 thao tác I/O giả (Task.Delay) song song đúng với Task.WhenAll + đo thời gian | 25 | So sánh với tuần tự |
Hàm async nhận CancellationToken và hủy được (ảnh/log) | 20 | |
IAsyncEnumerable hoặc channel mini: producer/consumer in log | 20 | Chọn một |
Không có .Result/.Wait() trong code lab | 10 | |
| README giải thích 1 rủi ro deadlock | 5 |
6.13.10.1 — Ngưỡng tổng điểm (Quiz 20 + Lab 80)
| Mức | Điểm | Ý nghĩa |
|---|---|---|
| Đạt | ≥ 70 | Đủ nền để học module kế mà không “lủng” kiến thức cốt lõi. |
| Khá | ≥ 85 | Có minh chứng code + nêu được liên hệ CRM rõ ràng trong README. |
| Giỏi | ≥ 95 | Có mở rộng / edge case / ADR ngắn / test bổ trợ (tùy rubric từng bài). |
6.13.11 — Phần C — Reflect & nối chuỗi (không chấm điểm)
Viết 5–8 câu (README hoặc docs/learning-log.md):
- Kiến thức module / project này sẽ được tái sử dụng trực tiếp ở module hoặc project CRM nào tiếp theo? (ghi tên module / P2 / P3 / Final).
- Nếu bỏ qua phần lab, rủi ro lớn nhất cho CRM ở giai đoạn sau là gì?
- Một quyết định kỹ thuật (nhỏ) bạn sẵn sàng ghi thành ADR một đoạn sau khi làm lab.
6.13.12 — Tài liệu tham khảo
- Asynchronous programming with async and await — Microsoft Docs
- Task asynchronous programming model — Microsoft Docs
- Cancellation in managed threads — Microsoft Docs
- System.Threading.Channels — Microsoft Docs
- IAsyncEnumerable — Microsoft Docs
- ConfigureAwait FAQ — Stephen Toub
- There is no thread — Stephen Cleary
- ValueTask — Understanding the Whys, Whats, and Whens — Stephen Toub
Bài tập tổng hợp
- Tóm tắt bài học bằng ngôn ngữ của bạn.
- Liên hệ nội dung với một tình huống thực tế trong dự án.
- Đề xuất một cải tiến cụ thể sau khi học bài này.
Tự kiểm tra
- Bạn có thể giải thích lại nội dung chính trong 2 phút không?
- Bạn có ví dụ áp dụng thực tế chưa?
- Bạn biết bước tiếp theo cần học/triển khai là gì không?
Kết luận
Hoàn thành bài này giúp bạn có góc nhìn đầy đủ hơn trước khi đi tiếp trong module.
Điều hướng
- Bài trước: 6.12 — Ví dụ thực tế nhanh
- Bài tiếp theo: Không có (bài cuối module).
- Về module: Trang mục lục