🔧 1. Use a Clean Architecture (Onion or Hexagonal)

Separate concerns clearly with layered architecture:

Layers:

Example Folder Structure:

/src

🧱 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:

This enforces compile-time separation and better boundaries.

🔄 6. Follow SOLID Principles

Here are the essential folder, solution, and project structures for large ASP.NET applications:

Solution Structure

Multi-Project Solution Layout:

Code
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:

Code
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:

Code
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):

Code
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

Code
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:

Code
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:

Code
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

Code
MyApp.BackgroundServices/
├── Jobs/
│   ├── OrderProcessingJob.cs
│   └── EmailSenderJob.cs
├── Services/
├── Configuration/
└── Extensions/

For Shared Libraries:

Code
MyApp.Shared.Kernel/
├── Extensions/
├── Utilities/
├── Constants/
├── Attributes/
└── Interfaces/

MyApp.Shared.Contracts/
├── Events/
├── Commands/
├── Queries/
└── DTOs/

Project Dependencies

Dependency Flow:

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

Code
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.