# Navigate to project root
cd C:\Users\me\RiderProjects\DotNetCleanArchitecture
# Restore and build
dotnet restore
dotnet build
# Run the API
cd src\DotNetCleanArchitecture.WebAPI
dotnet runThe API will start at: https://localhost:5001
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/products |
Get all products |
| GET | /api/products/{id} |
Get product by ID |
| POST | /api/products |
Create new product |
| PUT | /api/products/{id} |
Update product |
| DELETE | /api/products/{id} |
Delete product |
$body = @{
name = "Wireless Mouse"
description = "Ergonomic wireless mouse"
sku = "MOUSE-001"
price = 29.99
currency = "USD"
stockQuantity = 50
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://localhost:5001/api/products" `
-Method POST `
-Body $body `
-ContentType "application/json" `
-SkipCertificateCheckInvoke-RestMethod -Uri "https://localhost:5001/api/products" `
-Method GET `
-SkipCertificateCheck$productId = "YOUR-PRODUCT-ID-HERE"
Invoke-RestMethod -Uri "https://localhost:5001/api/products/$productId" `
-Method GET `
-SkipCertificateCheck$productId = "YOUR-PRODUCT-ID-HERE"
$body = @{
name = "Wireless Mouse Pro"
description = "Updated description"
price = 34.99
currency = "USD"
} | ConvertTo-Json
Invoke-RestMethod -Uri "https://localhost:5001/api/products/$productId" `
-Method PUT `
-Body $body `
-ContentType "application/json" `
-SkipCertificateCheck$productId = "YOUR-PRODUCT-ID-HERE"
Invoke-RestMethod -Uri "https://localhost:5001/api/products/$productId" `
-Method DELETE `
-SkipCertificateChecksrc/
├── Domain/ [No dependencies - Pure business logic]
│ ├── Common/ [Base classes]
│ │ ├── BaseEntity.cs
│ │ ├── IDomainEvent.cs
│ │ └── ValueObject.cs
│ ├── Entities/ [Aggregate roots]
│ │ └── Product.cs
│ ├── ValueObjects/ [Immutable values]
│ │ └── Money.cs
│ └── DomainEvents/ [Domain events]
│ ├── ProductCreatedDomainEvent.cs
│ ├── ProductUpdatedDomainEvent.cs
│ └── ProductStockChangedDomainEvent.cs
│
├── Application/ [Use cases & business orchestration]
│ ├── DTOs/ [Data transfer objects]
│ │ ├── ProductDto.cs
│ │ ├── CreateProductDto.cs
│ │ └── UpdateProductDto.cs
│ ├── Interfaces/ [Repository contracts]
│ │ ├── IProductRepository.cs
│ │ └── IUnitOfWork.cs
│ ├── UseCases/
│ │ └── Products/
│ │ ├── Commands/ [Write operations - CQRS]
│ │ │ ├── CreateProductCommand.cs
│ │ │ ├── UpdateProductCommand.cs
│ │ │ └── DeleteProductCommand.cs
│ │ └── Queries/ [Read operations - CQRS]
│ │ ├── GetAllProductsQuery.cs
│ │ └── GetProductByIdQuery.cs
│ └── DependencyInjection.cs
│
├── Infrastructure/ [External concerns implementation]
│ ├── Persistence/
│ │ ├── ApplicationDbContext.cs
│ │ ├── UnitOfWork.cs
│ │ ├── Configurations/
│ │ │ └── ProductConfiguration.cs
│ │ └── Repositories/
│ │ └── ProductRepository.cs
│ └── DependencyInjection.cs
│
└── WebAPI/ [HTTP API layer]
├── Controllers/
│ └── ProductsController.cs
├── Program.cs
└── Products.http [Test file]
- Domain: Business rules and entities (no dependencies)
- Application: Use cases and orchestration (depends on Domain)
- Infrastructure: Data access and external services (depends on Application)
- WebAPI: HTTP endpoints and presentation (depends on Application & Infrastructure)
- Aggregate Root:
Productentity encapsulates business logic - Value Objects:
Moneyrepresents immutable monetary values - Domain Events: Track important business events
- Factory Methods:
Product.Create()enforces invariants
- Commands: CreateProductCommand, UpdateProductCommand, DeleteProductCommand
- Queries: GetAllProductsQuery, GetProductByIdQuery
- Clear separation between read and write operations
- Interface in Application layer:
IProductRepository - Implementation in Infrastructure layer:
ProductRepository - Abstracts data access from business logic
IUnitOfWorkmanages transactions- Ensures consistency across multiple operations
// Factory method enforces business rules
var price = Money.Create(29.99m, "USD");
var product = Product.Create(
name: "Wireless Mouse",
description: "Ergonomic mouse",
sku: "MOUSE-001",
price: price,
stockQuantity: 50
);
// Business operations
product.AddStock(10); // Increases stock
product.RemoveStock(5); // Decreases stock
product.Activate(); // Activates product
product.Deactivate(); // Deactivates product// Inject the command in your controller
private readonly CreateProductCommand _createProductCommand;
// Execute the command
var dto = new CreateProductDto { /* ... */ };
var result = await _createProductCommand.ExecuteAsync(dto, cancellationToken);// Inject the query
private readonly GetAllProductsQuery _getAllProductsQuery;
// Execute the query
var products = await _getAllProductsQuery.ExecuteAsync(cancellationToken);Currently using InMemory database for easy testing.
- Products - Main product table with all fields
- Index on
Skucolumn (unique)
See PRODUCT_IMPLEMENTATION.md for detailed instructions.
✅ Solution builds successfully ✅ All layers properly separated ✅ Dependency injection configured ✅ Repository pattern implemented ✅ CQRS pattern implemented ✅ Domain events support ✅ Value objects (Money) ✅ EF Core configuration ✅ RESTful API endpoints ✅ InMemory database ready ✅ Error handling ✅ Logging integration
- IMPLEMENTATION_SUMMARY.md - Complete overview of implementation
- PRODUCT_IMPLEMENTATION.md - Detailed technical documentation
- README.md - Project overview and architecture
- QUICKSTART.md - This file (quick reference)
- Use the HTTP file: Open
Products.httpin Rider/VS Code for easy testing - Check logs: Console output shows detailed operation logs
- Domain logic: Business rules are in
Product.cs- start there - Add features: Extend by creating new commands/queries
- Testing: Each layer can be tested independently
# Change port in launchSettings.json or run on different port
dotnet run --urls "https://localhost:5002"# Trust the development certificate
dotnet dev-certs https --trust# Clean and rebuild
dotnet clean
dotnet restore
dotnet buildThe Product entity implementation is complete and follows all best practices. Start the application and begin testing the API!
Next: Open Products.http and start testing the endpoints! 🚀