Giới thiệu
Kiến trúc sạch (Clean Architecture) giúp duy trì khả năng bảo trì cho các ứng dụng lớn bằng cách thiết lập ranh giới rõ ràng giữa giao diện người dùng (UI), quy tắc kinh doanh và hạ tầng. Bài viết này sẽ hướng dẫn bạn cách thiết lập một API .NET kết hợp với Blazor Server sử dụng luồng phụ thuộc ba lớp cổ điển, cấu trúc thư mục có thể mở rộng và trường hợp sử dụng cụ thể được kết nối từ đầu đến cuối. Mẫu này được thiết kế để các tính năng có thể kiểm thử, hạ tầng có thể thay thế, và giao diện người dùng giữ được sự sạch sẽ.
Tại sao điều này quan trọng?
- Khả năng bảo trì: Các ranh giới ngăn chặn "rò rỉ logic" từ UI đến truy cập dữ liệu.
- Khả năng kiểm thử: Các trường hợp sử dụng thuần túy và dễ dàng để kiểm thử đơn vị.
- Tính linh hoạt: Hạ tầng (CSDL, khách hàng HTTP) có thể được thay thế mà không làm ảnh hưởng đến logic kinh doanh.
- Tốc độ phát triển: Các nhóm có thể làm việc song song trên Presentation, Application và Infrastructure mà không làm gián đoạn nhau.
Luồng phụ thuộc trong Kiến trúc Sạch
+-------------------+
| Presentation |
| (API / Blazor) |
+-------------------+
|
calls UseCases
|
+-------------------+
| Application |
| (UseCases & Ports)|
+-------------------+
|
uses Interfaces
|
+-------------------+
| Infrastructure |
| (Services/DB/API) |
+-------------------+
Các tham chiếu cho phép
- API phụ thuộc vào Application
- Application phụ thuộc vào Interfaces (cổng)
- Infrastructure triển khai Interfaces (bộ chuyển đổi) và được tiêm tại thời gian chạy
Điều này tuân thủ Nguyên tắc Đảo ngược Phụ thuộc: các lớp bên trong không biết về các lớp bên ngoài, và lớp Application điều phối chính sách, không phải hạ tầng.
Cấu trúc thư mục được khuyến nghị
/Portal
├── /API
│ ├── Controllers
│ └── Program.cs
├── /Application
│ ├── DTOs
│ ├── Interfaces
│ │ ├── Services
│ │ └── UseCases
│ ├── UseCases
│ │ └── NameSpace
│ └── Wrappers
├── /Domain (tùy chọn)
│ └── Entities
├── /Infrastructure
│ ├── Services
│ │ └── MyService.cs
│ └── HttpClients / DbContexts
└── /Tests
├── UnitTests
└── IntegrationTests
Ghi chú
- Presentation chỉ chứa UI và một số kết nối điểm cuối tối thiểu.
- Application chứa quy tắc kinh doanh, các trường hợp sử dụng và các giao diện trừu tượng (cổng).
- Infrastructure hoàn thành các giao diện đó (bộ chuyển đổi): khách hàng HTTP, kho dữ liệu CSDL, API bên ngoài.
- Domain là tùy chọn nếu bạn giữ các thực thể và logic miền riêng biệt.
Trường hợp sử dụng mẫu: Truy vấn Tham gia Đình công theo ngày
Lớp Application (trường hợp sử dụng)
Định nghĩa cổng (hợp đồng trường hợp sử dụng) và triển khai nó với logic điều phối chỉ - không có chi tiết HTTP/CSDL. Trường hợp sử dụng chỉ phụ thuộc vào một giao diện. Điều này làm cho nó thân thiện với việc kiểm thử đơn vị.
Lớp Infrastructure (triển khai dịch vụ)
Triển khai giao diện bằng cách sử dụng HttpClient/CSDL; ánh xạ các lỗi thô thành một bộ bao kết quả để giữ cho ứng dụng thuần túy.
Lớp API (bản đồ API tối thiểu)
API chỉ cần kết nối HTTP đến trường hợp sử dụng và trả về kết quả - không có logic kinh doanh.
Lợi ích
- Kiểm thử trường hợp sử dụng trong sự cô lập với một dịch vụ giả IStrikeParticipationService.
- Thay thế triển khai HTTP bằng một cơ sở dữ liệu hoặc một bộ chuyển đổi giả mà không chạm vào lớp Application.
- Giữ Program.cs tập trung vào sự kết hợp và DI.
Cách Blazor Server phù hợp
Blazor Server nằm trong Presentation, bên cạnh hoặc phía sau API. Các thành phần gọi API (hoặc gọi trực tiếp các trường hợp sử dụng nếu được lưu trữ trong cùng một tiến trình và bạn muốn không có ranh giới HTTP).
Giữ cho các trang/thành phần Blazor đơn giản: hiển thị trạng thái, gửi ý định và để các trường hợp sử dụng thực hiện điều phối.
Ví dụ đoạn mã thành phần Blazor (gọi API)
Mẹo: Nếu Blazor và API ở cùng một máy chủ, tiêm IGetStrikeParticipationByDateUseCase trực tiếp vào thành phần để có các cuộc gọi không tải; nếu bạn cần tách biệt (khả năng mở rộng, bảo mật, phiên bản), hãy đi qua API.
Chiến lược kiểm thử
- Kiểm thử Đơn vị (Application): Giả lập các phụ thuộc (ví dụ: IDataService) để kiểm thử logic trường hợp sử dụng độc lập và xác định.
- Kiểm thử Tích hợp (API): Sử dụng WebApplicationFactory để khởi động các điểm cuối API thực; thay thế các triển khai bằng các giả để kiểm soát.
- Kiểm thử Hợp đồng (Infrastructure): Xác thực các yêu cầu/phản hồi với các dịch vụ bên ngoài bằng cách sử dụng môi trường sandbox hoặc giả lập.
Các bài kiểm thử này nhanh chóng, xác định, và bao phủ luồng kinh doanh cốt lõi.
Kiểm thử tích hợp (API)
Sử dụng WebApplicationFactory để khởi động API.
Thay thế StrikeParticipationService bằng một giả thông qua DI để có các phản hồi xác định.
Xác minh các hợp đồng điểm cuối (mã trạng thái, hình dạng, phân trang, lỗi).
Kiểm thử hợp đồng (Infrastructure)
Nếu gọi các API bên ngoài thực, thêm một bộ kiểm thử chạy trên một sandbox/stub để xác thực khả năng tương thích yêu cầu/phản hồi.
Mở rộng và phát triển mẫu
- Thêm nhiều trường hợp sử dụng mà không cần chạm vào các bộ điều khiển.
- Thay thế các bộ chuyển đổi hạ tầng (HTTP → CSDL) mà không cần chạm vào các trường hợp sử dụng.
- Thêm bộ nhớ đệm tại lớp Infrastructure (ví dụ: Redis) phía sau cùng một giao diện.
- Giới thiệu CQRS nếu cần: các trường hợp sử dụng truy vấn cho đọc và các trường hợp sử dụng lệnh cho ghi.
- Thêm xác thực tại các ranh giới Application bằng cách sử dụng một bộ xác thực (FluentValidation) trước khi gọi dịch vụ.
Hướng dẫn và thực tiễn tốt nhất
- Giữ Presentation không có logic kinh doanh; nó điều phối đầu vào/đầu ra và ủy quyền cho các trường hợp sử dụng.
- Giữ Application không có kiến thức về hạ tầng; nó chỉ phụ thuộc vào các giao diện (cổng).
- Giữ Infrastructure không biết về UI; nó triển khai các cổng và xử lý các mối quan tâm bên ngoài.
- Ưu tiên tiêm constructor và các dịch vụ nhỏ, có thể kết hợp.
- Tập trung xử lý lỗi/kết quả với một bộ bao kết quả để có hành vi nhất quán giữa các lớp.
Kết luận
Thiết lập Kiến trúc Sạch này cung cấp một khung rõ ràng, có thể kiểm thử cho các nhóm phát triển ứng dụng .NET + Blazor Server. Mô hình trường hợp sử dụng giữ cho logic kinh doanh gắn kết và di động; hạ tầng dựa trên giao diện giữ cho các phụ thuộc trung thực và có thể thay thế; API vẫn mỏng và đáng tin cậy.
Bạn muốn một kho khởi động hoặc xuất đồ họa? Hãy để lại một bình luận, và một mẫu có thể tải xuống cùng với sơ đồ phụ thuộc có thể được chia sẻ.