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

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:

  1. Đổi tất cả method sang async Task<T>
  2. Dùng FirstOrDefaultAsync, ToListAsync, FindAsync, SaveChangesAsync
  3. Thêm CancellationToken ct = default vào mỗi method
  4. 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:

  1. Dùng Task.WhenAll chạy 3 service song song
  2. Áp dụng timeout 5 giây bằng CancellationTokenSource.CreateLinkedTokenSource
  3. Bắt lỗi từng task riêng lẻ, log, không fail toàn bộ
  4. 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:

  1. Dùng EF Core AsAsyncEnumerable() + yield return
  2. Áp dụng filter từ criteria
  3. ExportToCsvAsync dùng await foreach để ghi từng dòng
  4. Đả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ốngDO ✅DON'T ❌
Gọi DB / HTTPawait dbContext.X.ToListAsync(ct).ToList() trực tiếp
Chờ nhiều tasks độc lậpawait Task.WhenAll(t1, t2, t3)await t1; await t2; await t3;
Long-running operationPass CancellationToken xuyên suốtBỏ qua cancel
Library codeConfigureAwait(false)Không dùng ở app layer
Cần kết quả syncRefactor caller thành async.Result / .Wait()
Fire-and-forgetBắt exception bên trong task_ = DoAsync() không handle lỗi
Dataset lớnIAsyncEnumerable<T> streamLoad toàn bộ vào List<T>
CPU-bound backgroundawait Task.Run(...)async Task trực tiếp
Event handlerasync void + try/catchasync void không try/catch
Cache hot-pathValueTask<T>Task<T> mặc định cho mọi thứ

6.13.4 — Checklist code review

  • Mọi async method đều có await bên trong
  • CancellationToken được truyền từ controller xuống repository
  • Không có .Result hoặc .Wait() trừ trong Main hoặc test
  • Task.WhenAll được dùng thay vì await tuần tự cho tasks độc lập
  • async void chỉ 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# + P1Domain, 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 + P2Host, routing, validation, JWT, SignalR — CRM Backend API thực tế.
Giai đoạn 4 — Data + P3SQL, EF, cache, job, container — CRM ổn định & có thể triển khai.
Giai đoạn 5 — Senior + FinalClean 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ướcModule 5 — Advanced C#
Tiếp theoModule 7 — Dependency Injection

6.13.8 — Quy trình làm bài (hệ thống)

BướcViệc cần làmOutput nên có
1Làm Quiz trước, tự ghi đáp án + 1 dòng lý doKhô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ọc3–5 bullet “tôi đã hiểu…”
3Là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
4Tự 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.

  1. async Task method nên trả về gì khi không có giá trị?
    A. void B. Task C. int D. Thread

    Đáp án: B.

  2. 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.

  3. Deadlock điển hình khi mix sync/async?
    A. await trong lock B. .Result/.Wait() chặn context đang chờ continuation C. Dùng Task.Run quá ít D. GC.Collect()

    Đáp án: B (mô hình phổ biến).

  4. CancellationToken nên được?
    A. Bỏ qua trong API public B. Truyền xuống call stack async C. Chỉ dùng trong Main D. Thay thế try/catch

    Đáp án: B.

  5. async void nê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ểmGhi chú
3 thao tác I/O giả (Task.Delay) song song đúng với Task.WhenAll + đo thời gian25So 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 log20Chọn một
Không có .Result/.Wait() trong code lab10
README giải thích 1 rủi ro deadlock5

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á≥ 85Có minh chứng code + nêu được liên hệ CRM rõ ràng trong README.
Giỏi≥ 95Có 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):

  1. 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).
  2. Nếu bỏ qua phần lab, rủi ro lớn nhất cho CRM ở giai đoạn sau là gì?
  3. 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

Bài tập tổng hợp

  1. Tóm tắt bài học bằng ngôn ngữ của bạn.
  2. Liên hệ nội dung với một tình huống thực tế trong dự án.
  3. Đề 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