.NET Core  

Best Practice to Make your Project Cleaner in .NET Core

Introduction

In this article, we will see the Best practice to make your project cleaner in .NET Core.

Let's get started.

1. Project Structure and Layering

  • Separate your application into layers/projects:
    • API / UI Layer: ASP.NET Core Web API or MVC project.
    • Application Layer: Business logic, services, DTOs.
    • Domain Layer: Entities, domain logic, interfaces.
    • Infrastructure Layer: Data access (EF Core, repositories), external services.

Use solution folders to organize these projects.

/MyCleanProject
  /MyCleanProject.Api         <-- ASP.NET Core Web API
  /MyCleanProject.Application <-- Business Logic, Services, DTOs
  /MyCleanProject.Domain      <-- Entities, Interfaces
  /MyCleanProject.Infrastructure <-- EF Core, Repositories, Data Access
  /MyCleanProject.Tests       <-- Unit Tests

2. Use Dependency Injection (DI)

  • ASP.NET Core has built-in DI, use it to inject:
    • Services
    • Repositories
    • Logging
    • Configuration
  • Avoid new keyword inside your classes for dependencies.
  • Register services with appropriate lifetimes (Scoped, Singleton, Transient).

Example in Startup.cs or Program.cs (for .NET 6+ minimal hosting):

services.AddScoped<IUserService, UserService>();

services.AddSingleton<IMySingletonService, MySingletonService>();

3. Configuration Management

  • Use appsettings.json, appsettings.Development.json for environment-based settings.
  • Use IConfiguration interface injected wherever you need configuration values.
  • For secrets (API keys, passwords), use User Secrets in development and environment variables or Azure Key Vault in production.

4. Logging

  • Use ASP.NET Core’s built-in logging abstraction (ILogger<T>).
  • Configure structured logging providers like Serilog.
  • Write meaningful log messages at proper levels (Information, Warning, Error, etc.).

5. Use EF Core with Best Practices

  • Use Code-First or Database-First approach consistently.
  • Use DbContext with scoped lifetime.
  • Avoid exposing EF Core entities directly in APIs — use DTOs.
  • Use AsNoTracking() for read-only queries to improve performance.
  • Handle migrations properly with dotnet ef migrations.

6. API Design (if using Web API)

  • Use RESTful principles.
  • Return appropriate HTTP status codes.
  • Use DTOs or ViewModels instead of domain models.
  • Validate input using [DataAnnotations] and FluentValidation.
  • Use Model Binding and Model Validation built into ASP.NET Core.
  • Use ApiController attribute for automatic validation responses.

7. Middleware and Pipeline

  • Keep middleware modular and focused.
  • Use built-in middlewares for:
    • Exception handling (UseExceptionHandler or UseDeveloperExceptionPage)
    • Routing (UseRouting)
    • Authentication & Authorization
    • CORS (UseCors)
    • HTTPS redirection (UseHttpsRedirection)

8. Async Programming

  • Use async/await for I/O operations (database, HTTP calls).
  • Avoid blocking calls (.Result, .Wait()).

9. Testing

  • Unit test your business logic, services.
  • Use xUnit, Moq for mocking dependencies.
  • Integration test your API endpoints with WebApplicationFactory.

10. Security

  • Use ASP.NET Core Identity or JWT for authentication.
  • Protect sensitive endpoints with [Authorize].
  • Use HTTPS.
  • Validate all inputs.
  • Avoid exposing sensitive information in errors.

Example Minimal Startup Setup in .NET 6+

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddScoped<IUserService, UserService>();

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddLogging();
// Build the app
var app = builder.Build();
// Configure middleware pipeline
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Conclusion

Here we tried to cover Best practice to make your project cleaner in .NET Core.