How I like to Structure My .NET Backend Project - 10 More Days Left of 100 Days Challange

How I like to Structure My .NET Backend Project - 10 More Days Left of 100 Days Challange

After 40 days of MAUI, I have started to work on a project that I always intended to build with .NET. While working on that, I came up with the project organization strategy which I think will be well suited for API-based backends. This structural documentation is made with keeping 2 things in mind, simplicity and scalability. As much as we need rock solid structure of source code for enterprise application, in this era, speed is one of the most important thing we cannot deny.

In this article, I will walk through the design philosophy and organizational principles behind the source code of my backend project. This will help developers understand where to place their code and how to navigate through different parts of the system efficiently.

Purpose of the Structure

The primary goal of this source code structure is to:

  • Promote clarity and consistency
  • Maintain separation of concerns
  • Make the system scalable for multiple applications
  • Facilitate onboarding for new developers
  • Enforce a clean naming convention

Let’s explore how the codebase is logically divided.

?? Project Hierarchies

The source code is divided into hierarchies, which are top-level directories representing the logical layers of the system. Each hierarchy can contain folders based on taxonomies (explained later), and can support multiple application types (like Admin, User, etc.).

Note: All hierarchy folder names must be singular.

Here’s a breakdown of each hierarchy:

1. Module

Represents individual chunks of business logic. Think of them as feature-focused units. Examples: Auth, Advertise, File, Campaign

2. Provider

Contains the implementation of external service providers like databases, email services, schedulers, and caching systems. The business logic for using these providers will reside in the relevant module or service.

3. Settings

Holds application-level configuration data. Examples: Database connection strings, email credentials, private keys, etc.

4. Migration

Contains all the database migration scripts necessary for setting up and evolving the database schema.

5. HTTP

Home for utilities related to HTTP requests and responses, such as route prefixing and response standardization.

6. Common

Stores shared definitions like types, enums, and other constants used across the application.

7. Modifier

Includes elements like middlewares, filters, and attributes—components that modify the behavior of classes and requests.

8. Utils

A container for utility functions and ad-hoc tools that support the rest of the codebase.

?? Taxonomies

Taxonomies define the technological or functional role of a file. Each file in the project should represent only one taxonomy and should be named accordingly.

Here are the supported taxonomies:

  • Entity: Defines the database schema and serves as the core data model.
  • Dto: Stands for Data Transfer Object – used for API request/response types and functionality-specific data models.
  • Controller: Manages application routes and defines the HTTP endpoints.
  • Service: Contains all the business logic for each module or provider.
  • Repository: Responsible for implementing database queries. All DB operations must go through this layer.
  • Enum: Used for defining constant values shared across the application.
  • Helper: Holds utility functions that can be reused across different parts of the codebase.
  • Validator: Contains logic for validating HTTP request inputs.
  • Middleware: Defines HTTP middlewares to modify requests and responses.
  • Filter: Used to create class-level filters that apply conditional logic.
  • Attribute: Defines reusable attributes (decorators) for classes or methods.
  • Mapper: Handles object-to-object data transformation, especially for projections.

?? Application Types

The backend is designed to support multiple application types. Initially, the following two applications are defined:

  • Admin – The administrative interface used by internal users
  • User – The client-facing application for general users

Different application types may use the same modules or services but from different perspectives, enabling flexible scalability.

Naming Convention for Maintainance

A consistent naming convention is essential to support a well-structured codebase, as it reinforces the logical hierarchy and taxonomy outlined in the project’s architecture. It helps developers quickly understand the purpose and context of files, functions, and components, making the code easier to read, maintain, and scale across different modules and application types.

This naming convention system provides a consistent and structured approach to naming files, functions, and components across the project, ensuring clarity and maintainability. All files are expected to use PascalCase, with the exception of enums, which should follow UPPER_CASE_WITH_UNDERSCORES. File names are composed using the pattern {Module/Provider}{Taxonomy}.cs (e.g., AuthController.cs, FileRepository.cs) to reflect both the context and the function of the file. For context-specific providers, the format {ContextName}{Provider}.cs is followed (e.g., EmailProvider.cs).

Function names across services, controllers, and repositories are also standardized using PascalCase. Service functions begin with a verb and, if asynchronous, include the suffix Async (e.g., FetchAvailableProductsAsync). Controller functions mirror HTTP actions (e.g., GetUser, CreateCampaign), while repository methods follow a {Action}{Entity}By{Filter} format with optional With{ForeignField} or WithAll suffixes for joins. Projections use Dto for base models and a structured naming format for joined projections (e.g., UserProjection_PasswordDto). Enums are defined using PascalCase for the type and UPPER_CASE_WITH_UNDERSCORES for the values. This consistent naming strategy enhances readability, reduces confusion, and makes the codebase easier to scale and navigate.

?? Final Thoughts

This source code structure is designed with flexibility and clarity in mind. By dividing code into logical hierarchies and technological taxonomies, it becomes much easier to manage, scale, and onboard new developers.

Whether we're developing a new module, introducing a new provider, or simply trying to find where a particular type of logic resides, this structure provides clear guidance and consistency across the codebase.

Understanding and adhering to this structure is essential for maintaining high-quality backend code and achieving long-term project success.

Waythin Marma

Full-Stack Laravel Developer | API & Web Service | Server Deployment & Maintenance

4 天前

you better create a website and start uploading these, then add the google Adsense ??

Mohammad Abdullah-Al-Sajid Chowdhury

Finalist @ICPC Asia West Continent | Software Engineer

4 天前

Good stuff. Keep sharing.

Ariyan Jahangir

Software Engineer

4 天前

Useful tips Nice insight and a sweet getaway from the usual updates! Great stuff overall! Keep it up

要查看或添加评论,请登录

abtahi tajwar的更多文章