17 KiB
17 KiB
Template Microservice .NET 10
Template microservice .NET 10 cấp doanh nghiệp theo các pattern DDD, CQRS và Clean Architecture.
Tổng Quan
Template này cung cấp cấu trúc sẵn sàng production cho microservices .NET dựa trên kiến trúc tham chiếu eShopOnContainers với:
- Domain-Driven Design (DDD) - Aggregates, Entities, Value Objects, Domain Events
- CQRS Pattern - Tách biệt Commands (ghi) và Queries (đọc) với MediatR
- Clean Architecture - Phân tầng Domain, Infrastructure, API
- EF Core 10 - PostgreSQL với connection resilience
- FluentValidation - Validation request
- API Versioning - Versioning theo URL segment
- Health Checks - Probes sẵn sàng cho Kubernetes
- Structured Logging - Serilog với console và Seq
Yêu Cầu
| Yêu cầu | Phiên bản |
|---|---|
| .NET SDK | 10.0.101+ |
| Docker | 24.0+ |
| PostgreSQL | 15+ (hoặc dùng Docker) |
Bắt Đầu Nhanh
1. Tạo Service Mới
# Sao chép template sang service mới
cp -r services/_template_dot_net services/your-service-name-net
cd services/your-service-name-net
# Đổi tên tất cả "MyService" thành "YourService"
# Ví dụ: MyService → StorageService, UserService, PaymentService
find . -type f -name "*.cs" -exec sed -i '' 's/MyService/YourService/g' {} +
find . -type f -name "*.csproj" -exec sed -i '' 's/MyService/YourService/g' {} +
find . -type f -name "*.sln" -exec sed -i '' 's/MyService/YourService/g' {} +
Naming Convention:
- Service folder:
{service-name}-net(ví dụ:storage-service-net,iam-service-net) - Projects:
{ServiceName}.API,{ServiceName}.Domain,{ServiceName}.Infrastructure - DbContext:
{ServiceName}Context(ví dụ:StorageServiceContext) - Namespace:
GoodGo.Services.{ServiceName}(ví dụ:GoodGo.Services.StorageService)
2. Cấu Hình Môi Trường
cp .env.example .env
nano .env
3. Chạy với Docker
docker-compose up -d
docker-compose logs -f myservice-api
4. Chạy Local
dotnet restore
dotnet build
dotnet run --project src/MyService.API
Cấu Trúc Dự Án
{service-name}-net/ # Ví dụ: storage-service-net
├── src/
│ ├── {ServiceName}.API/ # Lớp Presentation (Controllers, CQRS)
│ │ ├── Controllers/ # Các API endpoints
│ │ ├── Application/ # Triển khai CQRS
│ │ │ ├── Commands/ # Thao tác ghi (MediatR)
│ │ │ ├── Queries/ # Thao tác đọc
│ │ │ ├── Behaviors/ # MediatR pipeline behaviors
│ │ │ └── Validations/ # FluentValidation validators
│ │ ├── Middlewares/ # Custom middlewares
│ │ └── Program.cs # Điểm vào ứng dụng
│ │
│ ├── {ServiceName}.Domain/ # Lớp Domain (Business logic thuần túy)
│ │ ├── AggregatesModel/ # Aggregate roots và entities
│ │ ├── Events/ # Domain events
│ │ ├── Exceptions/ # Domain exceptions
│ │ └── SeedWork/ # Base classes (Entity, IAggregateRoot)
│ │
│ └── {ServiceName}.Infrastructure/ # Lớp Infrastructure
│ ├── EntityConfigurations/ # Cấu hình EF Core (Fluent API)
│ ├── Repositories/ # Triển khai repositories
│ ├── Providers/ # External service providers (nếu có)
│ ├── Services/ # Infrastructure services
│ ├── Migrations/ # EF Core migrations
│ └── {ServiceName}Context.cs # DbContext với Unit of Work
│
├── tests/
│ ├── {ServiceName}.UnitTests/ # Unit tests
│ └── {ServiceName}.FunctionalTests/ # Integration tests
│
├── docs/
│ ├── en/ # English documentation
│ │ ├── README.md
│ │ └── ARCHITECTURE.md
│ └── vi/ # Vietnamese documentation
│ ├── README.md
│ └── ARCHITECTURE.md
│
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Thiết lập phát triển local
└── README.md # Service overview (bilingual)
Examples thực tế:
- Storage Service:
services/storage-service-net/ - IAM Service:
services/iam-service-net/ - Chat Service:
services/chat-service-net/
Kiến Trúc
graph TB
subgraph "Lớp API"
C[Controllers]
CMD[Commands]
Q[Queries]
B[Behaviors]
V[Validations]
end
subgraph "Lớp Domain"
AR[Aggregate Roots]
E[Entities]
VO[Value Objects]
DE[Domain Events]
end
subgraph "Lớp Infrastructure"
DB[(PostgreSQL)]
R[Repositories]
CTX[DbContext]
end
C --> CMD
C --> Q
CMD --> B --> V
CMD --> AR
Q --> R
R --> CTX --> DB
style C fill:#4a90d9,stroke:#2d5986,color:#fff
style AR fill:#50c878,stroke:#2d8659,color:#fff
style DB fill:#ff6b6b,stroke:#c0392b,color:#fff
Trách Nhiệm Các Lớp
1. Lớp Domain
- ZERO phụ thuộc bên ngoài (ngoại trừ MediatR.Contracts)
- Chỉ chứa các class POCO
- Triển khai các tactical patterns của DDD
| Thành phần | Mục Đích |
|---|---|
| SeedWork | Base classes: Entity, ValueObject, IAggregateRoot |
| AggregatesModel | Aggregate roots với entities và value objects |
| Events | Domain events cho giao tiếp cross-aggregate |
| Exceptions | Domain exceptions |
2. Lớp Infrastructure
- Truy cập database (EF Core)
- Triển khai repositories
- Tích hợp external services
3. Lớp API
- Controllers để xử lý HTTP
- Commands cho các thao tác ghi
- Queries cho các thao tác đọc
- MediatR behaviors cho cross-cutting concerns
Pattern CQRS
Commands (Thao Tác Ghi)
public record CreateSampleCommand(string Name, string? Description)
: IRequest<CreateSampleCommandResult>;
public class CreateSampleCommandHandler : IRequestHandler<CreateSampleCommand, CreateSampleCommandResult>
{
public async Task<CreateSampleCommandResult> Handle(CreateSampleCommand request, CancellationToken ct)
{
var sample = new Sample(request.Name, request.Description);
_repository.Add(sample);
await _repository.UnitOfWork.SaveEntitiesAsync(ct);
return new CreateSampleCommandResult(sample.Id);
}
}
Pipeline MediatR
Request → LoggingBehavior → ValidatorBehavior → TransactionBehavior → Handler → Response
Các API Endpoints
| Method | Endpoint | Mô Tả |
|---|---|---|
GET |
/api/v1/samples |
Lấy tất cả samples |
GET |
/api/v1/samples/{id} |
Lấy sample theo ID |
POST |
/api/v1/samples |
Tạo sample mới |
PUT |
/api/v1/samples/{id} |
Cập nhật sample |
DELETE |
/api/v1/samples/{id} |
Xóa sample |
PATCH |
/api/v1/samples/{id}/status |
Thay đổi trạng thái |
Health Endpoints
| Endpoint | Mục Đích |
|---|---|
/health |
Trạng thái health đầy đủ |
/health/live |
Kiểm tra sống |
/health/ready |
Kiểm tra sẵn sàng |
Biến Môi Trường
Required / Bắt buộc
| Biến | Mô Tả | Mặc định |
|---|---|---|
ASPNETCORE_ENVIRONMENT |
Tên môi trường | Development |
DATABASE_URL |
Kết nối Neon PostgreSQL | - |
ConnectionStrings__DefaultConnection |
Connection string format chuẩn | - |
Optional / Tùy chọn
| Biến | Mô Tả | Mặc định |
|---|---|---|
REDIS_URL |
Kết nối Redis (cache) | - |
RabbitMQ__Host |
RabbitMQ hostname | localhost |
RabbitMQ__Port |
RabbitMQ port | 5672 |
RabbitMQ__Username |
RabbitMQ username | guest |
RabbitMQ__Password |
RabbitMQ password | guest |
Inter-Service Communication
| Biến | Mô Tả | Mặc định |
|---|---|---|
IamService__BaseUrl |
IAM Service URL | http://iam-service-net:5001 |
Services__InternalApiKey |
Shared secret cho service-to-service auth | - |
Multi-Provider Pattern (Example: Storage Service)
| Biến | Mô Tả | Mặc định |
|---|---|---|
Storage__Provider |
Provider: minio hoặc aliyun |
minio |
Storage__DefaultBucket |
Default bucket name | storage |
Storage__MinIO__Endpoint |
MinIO endpoint | localhost:9000 |
Storage__MinIO__AccessKey |
MinIO access key | - |
Storage__MinIO__SecretKey |
MinIO secret key | - |
Storage__AliyunOSS__Endpoint |
Aliyun OSS endpoint | - |
Storage__AliyunOSS__AccessKeyId |
Aliyun access key | - |
Storage__AliyunOSS__AccessKeySecret |
Aliyun secret key | - |
Kiểm Thử
# Chạy tất cả tests
dotnet test
# Chạy với coverage
dotnet test /p:CollectCoverage=true /p:CoverageReportFormat=cobertura
# Chạy project test cụ thể
dotnet test tests/MyService.UnitTests
Triển Khai
Docker Build
docker build -t myservice:latest .
docker run -p 5000:8080 --env-file .env myservice:latest
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: myservice-api
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: myservice:latest
livenessProbe:
httpGet:
path: /health/live
port: 8080
readinessProbe:
httpGet:
path: /health/ready
port: 8080
Patterns Nâng cao
Multi-Provider Pattern
Sử dụng khi: Service cần hỗ trợ nhiều external providers (storage, payment, SMS)
Example: Storage Service với MinIO và Aliyun OSS
// Domain - Interface
public interface IStorageProvider
{
Task<string> UploadFileAsync(Stream fileStream, string fileName, CancellationToken ct);
Task<Stream> DownloadFileAsync(string objectKey, CancellationToken ct);
Task DeleteFileAsync(string objectKey, CancellationToken ct);
Task<string> GeneratePresignedUrlAsync(string objectKey, int expiryMinutes, CancellationToken ct);
}
// Infrastructure - MinIO Implementation
public class MinioStorageProvider : IStorageProvider
{
private readonly MinioClient _client;
// Implementation...
}
// Infrastructure - Aliyun OSS Implementation
public class AliyunOssStorageProvider : IStorageProvider
{
private readonly OssClient _client;
// Implementation...
}
// API - Provider Factory
public class StorageProviderFactory
{
public IStorageProvider CreateProvider(IConfiguration config)
{
var provider = config["Storage:Provider"];
return provider?.ToLower() switch
{
"minio" => new MinioStorageProvider(config),
"aliyun" => new AliyunOssStorageProvider(config),
_ => throw new InvalidOperationException($"Unknown provider: {provider}")
};
}
}
File Reference: StorageService.Infrastructure/Providers/
Inter-Service Authentication Pattern
Sử dụng khi: Service cần validate JWT tokens với IAM Service
// Infrastructure - IAM Service Client
public class IamServiceClient
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
public IamServiceClient(HttpClient httpClient, IConfiguration config)
{
_httpClient = httpClient;
_config = config;
_httpClient.BaseAddress = new Uri(_config["IamService:BaseUrl"]);
}
public async Task<UserInfo> ValidateTokenAsync(string token, CancellationToken ct)
{
var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/auth/validate")
{
Headers = { { "Authorization", $"Bearer {token}" } }
};
var response = await _httpClient.SendAsync(request, ct);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<UserInfo>(ct);
}
}
// API - Middleware
public class JwtValidationMiddleware
{
private readonly RequestDelegate _next;
private readonly IamServiceClient _iamClient;
public async Task InvokeAsync(HttpContext context)
{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (!string.IsNullOrEmpty(token))
{
var userInfo = await _iamClient.ValidateTokenAsync(token, context.RequestAborted);
context.Items["UserId"] = userInfo.UserId;
}
await _next(context);
}
}
Có Gì Mới Trong .NET 10
- Tính năng ngôn ngữ C# 14
- Hỗ trợ Native AOT được cải thiện
- Hiệu suất async/await tốt hơn
- JSON serialization được nâng cao (System.Text.Json)
- Hỗ trợ LTS 3 năm (đến tháng 11/2028)
- Entity Framework Core 10 với performance improvements
Tích hợp với Platform
Traefik Routing
Thêm labels vào docker-compose.yml:
services:
your-service-net:
build:
context: ../..
dockerfile: services/your-service-net/Dockerfile
labels:
- "traefik.enable=true"
- "traefik.http.routers.your-service.rule=PathPrefix(`/api/v1/your-service`)"
- "traefik.http.services.your-service.loadbalancer.server.port=8080"
- "traefik.http.routers.your-service.middlewares=strip-prefix@docker"
Neon PostgreSQL Configuration
{
"ConnectionStrings": {
"DefaultConnection": "Host=ep-xxx.neon.tech;Database=your_service;Username=xxx;Password=xxx;SSL Mode=Require;Trust Server Certificate=true"
}
}
Best Practices:
- Sử dụng connection pooling:
Pooling=true;Maximum Pool Size=100 - Enable SSL:
SSL Mode=Require - Set command timeout:
Command Timeout=30
RabbitMQ Integration (thay vì Kafka)
// Domain Event
public record FileUploadedEvent(string FileId, string UserId, long FileSize) : IDomainEvent;
// Infrastructure - Event Publisher
public class RabbitMqEventPublisher : IEventPublisher
{
private readonly IConnection _connection;
private readonly IModel _channel;
public async Task PublishAsync<T>(T @event, CancellationToken ct) where T : IDomainEvent
{
var message = JsonSerializer.Serialize(@event);
var body = Encoding.UTF8.GetBytes(message);
_channel.BasicPublish(
exchange: "domain_events",
routingKey: typeof(T).Name,
body: body
);
}
}
Tài Liệu Liên Quan
Architecture
- System Design - Kiến trúc tổng thể GoodGo Platform
- Microservices Communication - Patterns giao tiếp
- Caching Architecture - Chiến lược Redis caching
Skills
- CQRS with MediatR - CQRS pattern implementation
- Repository Pattern - EF Core repository pattern
- Domain-Driven Design - DDD tactical patterns
- Error Handling - Exception handling patterns
Guides
- Local Development - Setup môi trường dev
- Deployment - Deploy lên Kubernetes
Tài Nguyên Bổ sung
Microsoft Official
Architecture References
- eShopOnContainers - Microservices reference architecture
- .NET Microservices Architecture Book
Libraries
- MediatR - CQRS implementation
- FluentValidation - Validation library
- Polly - Resilience and transient-fault-handling
Tools
- EF Core Tools - Migrations và scaffolding
- Neon PostgreSQL - Serverless Postgres documentation
Last Updated: 2026-01-14
Template Version: 2.0
Maintained By: GoodGo Architecture Team