A comprehensive microservices architecture implementation using .NET 8 with Clean Architecture principles, DDD patterns, and reliable messaging.
This solution demonstrates a production-ready microservices architecture with:
- Clean Architecture - Separation of concerns with Domain, Application, Infrastructure, and API layers
- Domain-Driven Design - Aggregate roots, entities, value objects, and domain events
- CQRS - Command Query Responsibility Segregation using MediatR
- Event-Driven Architecture - Asynchronous communication via RabbitMQ and MassTransit
- Outbox/Inbox Patterns - Reliable messaging with guaranteed delivery and idempotency
- Microservices - Independent, deployable services with their own databases
- User registration and authentication
- JWT token generation and validation
- Refresh token support
- ASP.NET Core Identity with PostgreSQL
- Shopping basket management
- Redis-based storage for fast access
- JWT authentication required
- User-specific basket isolation
- Product catalog management
- PostgreSQL database
- Event publishing for product changes
- CQRS with MediatR
- Order processing
- Event-driven communication
- Consumes product and payment events
- Payment processing
- Event-driven communication
- Publishes payment events
Shared library containing:
- Domain primitives (Entity, ValueObject, AggregateRoot)
- Integration event base classes
- Outbox pattern implementation
- Inbox pattern implementation
- Idempotent consumer base class
- PostgreSQL - Product service and Identity service
- Redis - Basket service (in-memory storage)
- RabbitMQ - Event-driven communication between services
- Docker and Docker Compose
- .NET 8 SDK (for local development)
- Clone the repository
- Navigate to the project root
- Start all services:
docker-compose up --buildThis will start:
- PostgreSQL (port 5433)
- Redis (port 6379)
- RabbitMQ (ports 5672, 15672)
- Identity Service (port 5168)
- Basket Service (port 5169)
- Product Service (port 5165)
- Order Service (port 5166)
- Payment Service (port 5167)
- Swagger UIs: http://localhost:{port}/swagger
- RabbitMQ Management: http://localhost:15672 (guest/guest)
- Redis CLI:
docker exec -it cleanarch_redis redis-cli
curl -X POST http://localhost:5168/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123!",
"userName": "johndoe"
}'curl -X POST http://localhost:5168/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123!"
}'Response includes accessToken and refreshToken.
curl -X POST http://localhost:5169/api/basket/{userId}/items \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"productId": "product-123",
"productName": "Sample Product",
"price": 29.99,
"quantity": 2
}'curl -X GET http://localhost:5169/api/basket/{userId} \
-H "Authorization: Bearer {accessToken}"CleanArch.sln
├── CleanArch.BuildingBlocks/ # Shared library
│ ├── Domain/ # Domain primitives
│ ├── IntegrationEvents/ # Event base classes
│ ├── Outbox/ # Outbox pattern
│ └── Inbox/ # Inbox pattern
├── CleanArch.Identity.Api/ # Identity service
├── CleanArch.Basket.Api/ # Basket service
├── CleanArch.Api/ # Product service
├── CleanArch.Order.Api/ # Order service
├── CleanArch.Payment.Api/ # Payment service
├── CleanArch.Domain/ # Domain layer
├── CleanArch.Application/ # Application layer
├── CleanArch.Infrastructure/ # Infrastructure layer
├── CleanArch.Contracts/ # Shared contracts
└── docker-compose.yml # Docker orchestration
Ensures reliable message publishing by storing events in the database before publishing to the message broker. A background service polls for unprocessed messages and publishes them.
Benefits:
- Guaranteed message delivery
- Transactional consistency
- Resilience to message broker failures
Ensures idempotent message processing by tracking processed message IDs. Duplicate messages are automatically ignored.
Benefits:
- Prevents duplicate processing
- Handles message redelivery
- Maintains data consistency
Separates read and write operations using MediatR commands and queries.
Benefits:
- Optimized read/write models
- Scalability
- Clear separation of concerns
All services use the same JWT configuration for authentication:
{
"Jwt": {
"Secret": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!",
"Issuer": "CleanArch.Identity",
"Audience": "CleanArch.Api",
"ExpiryMinutes": "60"
}
}Important: Change the JWT secret in production!
Services use environment variables for database connections (configured in docker-compose.yml):
- Product Service:
Host=postgres;Port=5432;Database=CleanArchDb - Identity Service:
Host=postgres;Port=5432;Database=CleanArchIdentityDb - Basket Service:
redis:6379
dotnet build CleanArch.slndotnet test CleanArch.UnitTests/CleanArch.UnitTests.csproj# Identity Service
dotnet run --project CleanArch.Identity.Api/CleanArch.Identity.Api.csproj
# Basket Service
dotnet run --project CleanArch.Basket.Api/CleanArch.Basket.Api.csproj
# Product Service
dotnet run --project CleanArch.Api/CleanArch.Api.csprojTo complete the Outbox/Inbox integration:
- Add
OutboxMessageandInboxMessageDbSets to existing service DbContexts - Register
OutboxRepositoryandInboxRepositoryin service DI containers - Register
OutboxProcessorServiceas a hosted service - Update event publishers to use the Outbox pattern
- Update consumers to inherit from
IdempotentConsumer<T> - Run database migrations to create Outbox/Inbox tables
See the walkthrough document for detailed integration steps.
This project is for educational and demonstration purposes.