๐ง 1. Use a Clean Architecture (Onion or Hexagonal)
Separate concerns clearly with layered architecture:
Layers:
- Presentation/UI (ASP.NET MVC/Razor Pages/API Controllers)
- Application (Use cases, commands, queries, interfaces)
- Domain (Entities, value objects, business rules)
- Infrastructure (Database, file system, email, external APIs)
Example Folder Structure:
/src
/Web (Presentation Layer)
/Application
/Domain
/Infrastructure
/tests
/UnitTests
/IntegrationTests
๐งฑ 2. Modularize by Feature, Not Type
Avoid grouping files by technical type (e.g., Controllers, Models, Views). Instead, use feature folders:
/Features
/Orders
OrderController.cs
OrderService.cs
Order.cs
/Products
ProductController.cs
ProductService.cs
Product.cs
This improves encapsulation and makes features easier to test and modify.
๐ฆ 3. Use Dependency Injection Everywhere
Rely on ASP.NET Core’s built-in DI system. Avoid static classes or service locators.
Register interfaces and implementations in Startup.cs
or via extension methods in Infrastructure
.
๐งช 4. Separate Test Projects
Maintain dedicated test projects for unit and integration tests, mirroring the structure of the main app.
/tests
/App.UnitTests
/App.IntegrationTests
๐ 5. Use Projects for Separation
Split into multiple class libraries:
MyApp.Web
MyApp.Application
MyApp.Domain
MyApp.Infrastructure
This enforces compile-time separation and better boundaries.
๐ 6. Follow SOLID Principles
- Single Responsibility: One class = one job.
- Open/Closed: Code open for extension, closed for modification.
- Liskov: Use base classes/interfaces safely.
- Interface Segregation: Prefer small interfaces.
- Dependency Inversion: Depend on abstractions.
Here are the essential folder, solution, and project structures for large ASP.NET applications:
Solution Structure
Multi-Project Solution Layout:
MySolution.sln
โโโ src/
โ โโโ MyApp.Domain/
โ โโโ MyApp.Application/
โ โโโ MyApp.Infrastructure/
โ โโโ MyApp.Web.API/
โ โโโ MyApp.Web.MVC/
โ โโโ MyApp.Shared/
โโโ tests/
โ โโโ MyApp.Domain.Tests/
โ โโโ MyApp.Application.Tests/
โ โโโ MyApp.Infrastructure.Tests/
โ โโโ MyApp.Integration.Tests/
โโโ docs/
โโโ scripts/
โโโ tools/
For Microservices/Multiple Bounded Contexts:
MySolution.sln
โโโ src/
โ โโโ Services/
โ โ โโโ MyApp.Orders/
โ โ โ โโโ MyApp.Orders.API/
โ โ โ โโโ MyApp.Orders.Domain/
โ โ โ โโโ MyApp.Orders.Infrastructure/
โ โ โโโ MyApp.Users/
โ โ โโโ MyApp.Inventory/
โ โโโ Shared/
โ โ โโโ MyApp.Shared.Kernel/
โ โ โโโ MyApp.Shared.Infrastructure/
โ โ โโโ MyApp.Shared.Contracts/
โ โโโ Gateways/
โ โโโ MyApp.API.Gateway/
Project Structure Patterns
Clean Architecture Project Layout:
MyApp.Domain/
โโโ Entities/
โโโ ValueObjects/
โโโ Enums/
โโโ Interfaces/
โโโ Events/
โโโ Exceptions/
โโโ Specifications/
MyApp.Application/
โโโ Commands/
โโโ Queries/
โโโ Handlers/
โโโ Services/
โโโ Interfaces/
โโโ DTOs/
โโโ Mappings/
โโโ Validators/
MyApp.Infrastructure/
โโโ Data/
โ โโโ Configurations/
โ โโโ Migrations/
โ โโโ Repositories/
โโโ Services/
โโโ External/
โโโ Caching/
MyApp.Web.API/
โโโ Controllers/
โโโ Middleware/
โโโ Filters/
โโโ Models/
โ โโโ Requests/
โ โโโ Responses/
โโโ Configuration/
โโโ Extensions/
Feature-Based Structure (Alternative):
MyApp.Web.API/
โโโ Features/
โ โโโ Orders/
โ โ โโโ GetOrder/
โ โ โ โโโ GetOrderQuery.cs
โ โ โ โโโ GetOrderHandler.cs
โ โ โ โโโ GetOrderValidator.cs
โ โ โโโ CreateOrder/
โ โ โโโ OrdersController.cs
โ โโโ Users/
โ โโโ Products/
โโโ Common/
โ โโโ Behaviors/
โ โโโ Exceptions/
โ โโโ Extensions/
โโโ Infrastructure/
Folder Organization Within Projects
MyApp.Domain/
โโโ Aggregates/
โ โโโ Order/
โ โ โโโ Order.cs
โ โ โโโ OrderItem.cs
โ โ โโโ IOrderRepository.cs
โ โโโ User/
โโโ Common/
โ โโโ BaseEntity.cs
โ โโโ IAggregateRoot.cs
โ โโโ DomainEvent.cs
โโโ ValueObjects/
โ โโโ Money.cs
โ โโโ Address.cs
โ โโโ Email.cs
โโโ Exceptions/
โโโ DomainException.cs
Infrastructure Project Structure:
MyApp.Infrastructure/
โโโ Data/
โ โโโ Context/
โ โ โโโ ApplicationDbContext.cs
โ โโโ Configurations/
โ โ โโโ OrderConfiguration.cs
โ โ โโโ UserConfiguration.cs
โ โโโ Repositories/
โ โ โโโ OrderRepository.cs
โ โ โโโ BaseRepository.cs
โ โโโ Migrations/
โโโ Services/
โ โโโ EmailService.cs
โ โโโ FileStorageService.cs
โโโ External/
โ โโโ PaymentGateway/
โ โโโ NotificationService/
โโโ Caching/
โโโ RedisCacheService.cs
API Project Structure:
MyApp.Web.API/
โโโ Controllers/
โ โโโ V1/
โ โ โโโ OrdersController.cs
โ โ โโโ UsersController.cs
โ โโโ V2/
โโโ Models/
โ โโโ Requests/
โ โ โโโ CreateOrderRequest.cs
โ โ โโโ UpdateOrderRequest.cs
โ โโโ Responses/
โ โ โโโ OrderResponse.cs
โ โโโ Common/
โ โโโ PagedResponse.cs
โโโ Middleware/
โ โโโ ExceptionHandlingMiddleware.cs
โ โโโ RequestLoggingMiddleware.cs
โโโ Filters/
โ โโโ ValidateModelFilter.cs
โโโ Configuration/
โ โโโ DependencyInjection.cs
โ โโโ SwaggerConfiguration.cs
โโโ Extensions/
โโโ ServiceCollectionExtensions.cs
Specialized Structures
MyApp.BackgroundServices/
โโโ Jobs/
โ โโโ OrderProcessingJob.cs
โ โโโ EmailSenderJob.cs
โโโ Services/
โโโ Configuration/
โโโ Extensions/
For Shared Libraries:
MyApp.Shared.Kernel/
โโโ Extensions/
โโโ Utilities/
โโโ Constants/
โโโ Attributes/
โโโ Interfaces/
MyApp.Shared.Contracts/
โโโ Events/
โโโ Commands/
โโโ Queries/
โโโ DTOs/
Project Dependencies
Dependency Flow:
- Web.API → Application + Infrastructure
- Application → Domain only
- Infrastructure → Domain + Application (for interfaces)
- Domain → No dependencies
- Shared.Kernel → No dependencies
- Shared.Contracts → Shared.Kernel only
File Naming Conventions
Controllers: OrdersController.cs
, UsersController.cs
Services: IOrderService.cs
, OrderService.cs
Repositories: IOrderRepository.cs
, OrderRepository.cs
DTOs: CreateOrderDto.cs
, OrderResponseDto.cs
Commands/Queries: CreateOrderCommand.cs
, GetOrderQuery.cs
Handlers: CreateOrderCommandHandler.cs
, GetOrderQueryHandler.cs
Configuration Files Organization
MyApp.Web.API/
โโโ appsettings.json
โโโ appsettings.Development.json
โโโ appsettings.Production.json
โโโ appsettings.Staging.json
โโโ Configuration/
โโโ DatabaseSettings.cs
โโโ JwtSettings.cs
โโโ ExternalServiceSettings.cs
This structure provides clear separation of concerns, makes navigation intuitive for large teams, and scales well as your application grows. The key is consistency across all projects and establishing clear naming conventions that everyone follows.