# 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

```bash
# 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

```bash
cp .env.example .env
nano .env
```

### 3. Chạy với Docker

```bash
docker-compose up -d
docker-compose logs -f myservice-api
```

### 4. Chạy Local

```bash
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/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net)
- IAM Service: [`services/iam-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/iam-service-net)
- Chat Service: [`services/chat-service-net/`](file:///Users/velikho/Desktop/WORKING/Base/services/chat-service-net)

## Kiến Trúc

```mermaid
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)

```csharp
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ử

```bash
# 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

```bash
docker build -t myservice:latest .
docker run -p 5000:8080 --env-file .env myservice:latest
```

### Kubernetes

```yaml
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

```csharp
// 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/`](file:///Users/velikho/Desktop/WORKING/Base/services/storage-service-net/src/StorageService.Infrastructure/Providers)

---

### Inter-Service Authentication Pattern

**Sử dụng khi**: Service cần validate JWT tokens với IAM Service

```csharp
// 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`:

```yaml
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

```json
{
  "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)

```csharp
// 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](../architecture/system-design.md) - Kiến trúc tổng thể GoodGo Platform
- [Microservices Communication](../architecture/microservices-communication.md) - Patterns giao tiếp
- [Caching Architecture](../architecture/caching-architecture.md) - Chiến lược Redis caching

### Skills
- [CQRS with MediatR](../skills/cqrs-mediatr.md) - CQRS pattern implementation
- [Repository Pattern](../skills/repository-pattern.md) - EF Core repository pattern
- [Domain-Driven Design](../skills/domain-driven-design.md) - DDD tactical patterns
- [Error Handling](../skills/error-handling-patterns.md) - Exception handling patterns

### Guides
- [Local Development](../guides/local-development.md) - Setup môi trường dev
- [Deployment](../guides/deployment.md) - Deploy lên Kubernetes

## Tài Nguyên Bổ sung

### Microsoft Official
- [.NET 10 Documentation](https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10)
- [Entity Framework Core 10](https://docs.microsoft.com/en-us/ef/core/)
- [ASP.NET Core 10](https://docs.microsoft.com/en-us/aspnet/core/)

### Architecture References
- [eShopOnContainers](https://github.com/dotnet-architecture/eShopOnContainers) - Microservices reference architecture
- [.NET Microservices Architecture Book](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/)

### Libraries
- [MediatR](https://github.com/jbogard/MediatR) - CQRS implementation
- [FluentValidation](https://docs.fluentvalidation.net/) - Validation library
- [Polly](https://github.com/App-vNext/Polly) - Resilience and transient-fault-handling

### Tools
- [EF Core Tools](https://docs.microsoft.com/en-us/ef/core/cli/dotnet) - Migrations và scaffolding
- [Neon PostgreSQL](https://neon.tech/docs) - Serverless Postgres documentation

---

**Last Updated**: 2026-01-14  
**Template Version**: 2.0  
**Maintained By**: GoodGo Architecture Team
