Skip to content

throwExceptions/Boilerplate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ .NET Boilerplate Project

A production-ready .NET 10 boilerplate project following Clean Architecture principles with MongoDB (Azure Cosmos DB) integration.

.NET Version C# Version License

πŸ“‹ Table of Contents


πŸ—οΈ Architecture

Clean Architecture (4 Layers)

Boilerplate/
β”œβ”€β”€ API/              # Presentation Layer
β”œβ”€β”€ Application/      # Application Layer (Use Cases)
β”œβ”€β”€ Domain/           # Domain Layer (Business Logic)
└── Infra/            # Infrastructure Layer (External Services)

Dependency Flow: API β†’ Application β†’ Domain ← Infra

Key Principles:

  • βœ… Domain is independent (no external dependencies)
  • βœ… Application contains business use cases (CQRS with MediatR)
  • βœ… Infrastructure implements interfaces from Domain
  • βœ… API is thin (controllers delegate to Application layer)

πŸ“ Project Structure

API (Presentation Layer)

API/
β”œβ”€β”€ Controllers/
β”‚   β”œβ”€β”€ BaseController.cs           # Base controller with TryExecuteAsync pattern
β”‚   └── SampleController.cs          # CRUD endpoints
β”œβ”€β”€ DTOs/
β”‚   β”œβ”€β”€ Request/
β”‚   β”‚   β”œβ”€β”€ CreateSampleRequestDto.cs # No Id (generated by DB)
β”‚   β”‚   β”œβ”€β”€ GetSampleRequestDto.cs    # With string Id
β”‚   β”‚   β”œβ”€β”€ UpdateSampleRequestDto.cs # With string Id
β”‚   β”‚   └── Validators/              # FluentValidation validators
β”‚   └── Response/
β”‚       β”œβ”€β”€ BaseResponseDto.cs       # Generic response wrapper
β”‚       └── *ResponseDto.cs          # Specific response DTOs
β”œβ”€β”€ Exceptions/
β”‚   β”œβ”€β”€ BadRequestException.cs
β”‚   β”œβ”€β”€ DuplicateException.cs
β”‚   └── FormValidationException.cs
└── appsettings.json                # Configuration (secrets in User Secrets)

Application (Use Cases)

Application/
β”œβ”€β”€ Commands/
β”‚   β”œβ”€β”€ CreateSampleCommand.cs
β”‚   β”œβ”€β”€ CreateSampleCommandHandler.cs
β”‚   β”œβ”€β”€ UpdateSampleCommand.cs
β”‚   └── UpdateSampleCommandHandler.cs
β”œβ”€β”€ Queries/
β”‚   β”œβ”€β”€ SampleQuery.cs
β”‚   └── SampleQueryHandler.cs
└── Clients/
    └── ISampleClient.cs             # Interface for external APIs

Domain (Business Logic)

Domain/
β”œβ”€β”€ Models/
β”‚   └── Sample.cs                    # Domain model (string Id for MongoDB)
β”œβ”€β”€ Entities/
β”‚   β”œβ”€β”€ BaseEntity.cs                # MongoDB base (Id, CreatedAt, UpdatedAt)
β”‚   └── SampleEntity.cs              # MongoDB-specific entity
β”œβ”€β”€ Repositories/
β”‚   └── ISampleRepository.cs         # Repository interface
β”œβ”€β”€ MappingConfiguration/
β”‚   β”œβ”€β”€ SampleToSampleDto.cs         # Mapster mappings
β”‚   └── SampleEntityMapping.cs       # Entity ↔ Model mapping
└── Enums/
    └── ErrorType.cs

Infra (Infrastructure)

Infra/
β”œβ”€β”€ Repositories/
β”‚   └── SampleRepository.cs          # MongoDB implementation
β”œβ”€β”€ Clients/
β”‚   └── SampleClient.cs              # External API client
β”œβ”€β”€ Settings/
β”‚   β”œβ”€β”€ MongoDbSettings.cs
β”‚   └── SampleConfiguration.cs
β”œβ”€β”€ Extensions/
β”‚   β”œβ”€β”€ UrlExtensions.cs
β”‚   └── JsonExtension.cs
└── Infrastructure.cs                # DI registration

πŸ› οΈ Technology Stack

Component Technology Version
Framework .NET 10
Language C# 14.0
Database Azure Cosmos DB MongoDB API
Driver MongoDB.Driver Latest
Mediator MediatR Latest
Mapping Mapster Latest
Validation FluentValidation Latest
Logging Serilog Latest
Testing xUnit + Moq Latest

πŸš€ Getting Started

Prerequisites

  • .NET 10 SDK
  • Azure Cosmos DB account (MongoDB API) or local MongoDB
  • Visual Studio 2022 / VS Code / Rider

Installation

1. Clone the repository

git clone https://github.com/throwExceptions/thenorsound.git
cd thenorsound/Boilerplate

2. Install packages

dotnet restore

3. Set up User Secrets (for local development)

cd API
dotnet user-secrets init
dotnet user-secrets set "MongoDbSettings:ConnectionString" "mongodb+srv://user:password@..."
dotnet user-secrets set "MongoDbSettings:DatabaseName" "boilerplate-mongodb"
dotnet user-secrets set "MongoDbSettings:SampleCollectionName" "Samples"

4. Run the application

dotnet run --project API

5. Open Swagger UI

https://localhost:5001

🎯 Design Patterns & Principles

1. CQRS (Command Query Responsibility Segregation)

Commands (Write operations):

  • CreateSampleCommand β†’ CreateSampleCommandHandler
  • UpdateSampleCommand β†’ UpdateSampleCommandHandler

Queries (Read operations):

  • SampleQuery β†’ SampleQueryHandler

2. Repository Pattern

  • Domain defines ISampleRepository interface
  • Infrastructure implements SampleRepository with MongoDB logic
  • Application uses repository through DI

3. Dependency Injection

Using Primary Constructors (C# 12+):

public class SampleController(IMediator mediator, ILogger logger)
{
    public async Task<IActionResult> Create(CreateSampleRequestDto request)
    {
        var command = new CreateSampleCommand(request);
        var result = await mediator.Send(command);
        return Ok(result);
    }
}

πŸ“ Code Conventions

C# Language Features

// βœ… Primary Constructors
public class SampleController(IMediator mediator, ILogger logger)

// βœ… File-scoped namespaces
namespace API.Controllers;

// βœ… Expression-bodied members
public DateTime? UpdatedAt { get => _updatedAt; set => _updatedAt = value; }

// βœ… Using statements inside namespace (StyleCop SA1200)
namespace API.Controllers;
using System;
using MediatR;

Naming Conventions

Type Convention Example
Classes PascalCase SampleController
Interfaces IPascalCase ISampleRepository
Methods PascalCase GetByIdAsync
Properties PascalCase ConnectionString
Private fields _camelCase _samples
Parameters camelCase request
Async methods SuffixAsync CreateAsync

StyleCop Rules

File Header (SA1633): Include license headers in all source files

// Copyright (c) ThenorSound. All rights reserved.
// Licensed under the MIT License.
namespace API.Controllers;

πŸ—„οΈ MongoDB Integration

BaseEntity Pattern

public abstract class BaseEntity
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    [BsonElement("createdAt")]
    public DateTime CreatedAt { get; set; }

    [BsonElement("updatedAt")]
    public DateTime? UpdatedAt { get; set; }
}

MongoDB ObjectId

  • Type: string
  • Format: 24 hexadecimal characters (e.g., 507f1f77bcf86cd799439011)
  • Validation: .Length(24).Matches("^[a-f0-9]{24}$")

Important Rules:

  • CreatedAt is set automatically when entity is first saved (lazy getter)
  • UpdatedAt is set explicitly in Repository's UpdateAsync method
  • ObjectId is always a string in this architecture

πŸ” Configuration & Secrets

Local Development: User Secrets

Never commit secrets to Git!

cd API
dotnet user-secrets init
dotnet user-secrets set "MongoDbSettings:ConnectionString" "mongodb+srv://user:password@..."
dotnet user-secrets set "MongoDbSettings:DatabaseName" "boilerplate-mongodb"
dotnet user-secrets set "MongoDbSettings:SampleCollectionName" "Samples"

Azure Deployment: Environment Variables

In Azure App Service β†’ Configuration β†’ Application settings:

MongoDbSettings__ConnectionString = mongodb+srv://...
MongoDbSettings__DatabaseName = boilerplate-mongodb
MongoDbSettings__SampleCollectionName = Samples

⚠️ Note: Use double underscore __ instead of colon : for nested config.

Configuration Priority

  1. User Secrets (highest - local development)
  2. Environment Variables (Azure)
  3. appsettings.json (lowest - defaults)

🎨 API Design

DTO Design Rules

DTO Type Id Field Usage
CreateRequestDto ❌ No Id Create new resource
GetRequestDto βœ… string Id Retrieve resource
UpdateRequestDto βœ… string Id Update resource
ResponseDto βœ… string Id Return data

πŸ§ͺ Testing

Unit Tests with xUnit

public class SampleControllerTests
{
    [Fact]
    public async Task Create_WithValidRequest_ReturnsOk()
    {
        // Arrange
        var mediatorMock = new Mock<IMediator>();
        var controller = new SampleController(mediatorMock.Object, Mock.Of<ILogger>());
        var request = new CreateSampleRequestDto { Name = "Test" };

        // Act
        var result = await controller.Create(request);

        // Assert
        Assert.IsType<OkObjectResult>(result);
    }
}

πŸš€ Deployment

Azure Cosmos DB Setup

1. Create Cosmos DB Account

  • API: MongoDB
  • Tier: Free tier (for development)
  • Location: North Europe

2. Database & Collection

  • Database: boilerplate-mongodb (auto-created on first write)
  • Collection: Samples (auto-created on first write)

3. Networking

  • Enable Public Access
  • Add your IP address
  • Allow Azure services

4. Get Connection String

  • Cosmos DB β†’ Connection strings
  • Copy "Self (always this cluster)" connection string

Azure App Service Deployment

1. Create App Service

az webapp create \
  --resource-group rg-boilerplate \
  --plan boilerplate-plan \
  --name boilerplate-api \
  --runtime "DOTNET|10.0"

2. Configure Environment Variables

az webapp config appsettings set \
  --name boilerplate-api \
  --resource-group rg-boilerplate \
  --settings \
  MongoDbSettings__ConnectionString="mongodb+srv://..." \
  MongoDbSettings__DatabaseName="boilerplate-mongodb" \
  MongoDbSettings__SampleCollectionName="Samples"

3. Deploy

dotnet publish -c Release
az webapp deploy \
  --resource-group rg-boilerplate \
  --name boilerplate-api \
  --src-path ./bin/Release/net10.0/publish.zip

πŸ“ Useful Commands

Build

dotnet build

Run

dotnet run --project API

Test

dotnet test

Watch mode (auto-rebuild on changes)

dotnet watch --project API

User Secrets

dotnet user-secrets init --project API
dotnet user-secrets set "Key" "Value" --project API
dotnet user-secrets list --project API
dotnet user-secrets clear --project API

Add NuGet Package

dotnet add [Project] package [PackageName]

Update packages

dotnet list package --outdated
dotnet add package [PackageName]

πŸ“š Project Dependencies

API

  • Microsoft.AspNetCore.OpenApi
  • Swashbuckle.AspNetCore
  • FluentValidation
  • Serilog.AspNetCore
  • Serilog.Sinks.Console
  • Serilog.Sinks.File

Application

  • MediatR
  • Mapster

Domain

  • MongoDB.Bson
  • Mapster

Infra

  • MongoDB.Driver
  • Mapster
  • MapsterMapper

πŸ”§ Infrastructure Setup

MongoDB Registration (Infrastructure.cs)

public static IServiceCollection AddInfrastructure(
    this IServiceCollection services,
    IConfiguration configuration)
{
    services.Configure<MongoDbSettings>(
        configuration.GetSection(nameof(MongoDbSettings)));

    services.AddSingleton<IMongoClient>(
        new MongoClient(configuration["MongoDbSettings:ConnectionString"]));

    services.AddScoped<ISampleRepository, SampleRepository>();
    services.AddScoped<ISampleClient, SampleClient>();

    return services;
}

Mapster Registration

public static IServiceCollection AddMappings(this IServiceCollection services)
{
    TypeAdapterConfig.GlobalSettings
        .Scan(typeof(SampleToSampleDto).Assembly);

    services.AddScoped<IMapper, ServiceMapper>();

    return services;
}

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Code Style

  • Follow StyleCop rules (SA*)
  • All public members must have XML documentation
  • Use primary constructors where possible
  • Prefer this. prefix for all class members
  • Use file-scoped namespaces
  • Use expression-bodied members when appropriate

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ™ Acknowledgments

  • Clean Architecture by Robert C. Martin
  • MediatR for CQRS implementation
  • Mapster for high-performance object mapping
  • FluentValidation for validation rules
  • MongoDB.Driver for database access
  • Serilog for structured logging

πŸ“ž Contact

Project Link: https://github.com/throwExceptions/thenorsound


πŸŽ“ Key Takeaways

For New Developers on this Project:

  1. Architecture: Follow Clean Architecture - Domain is the core, never reference infrastructure
  2. IDs: Always use string for MongoDB ObjectIds (24 hex characters)
  3. Timestamps: CreatedAt uses lazy getter, UpdatedAt is set explicitly in Repository
  4. DTOs: Create requests don't have Id, Get/Update requests do
  5. Secrets: Use User Secrets locally, Environment Variables in Azure
  6. Mapping: Use Mapster with .Ignore() for auto-managed properties
  7. Validation: FluentValidation for all request DTOs
  8. Testing: xUnit + Moq for unit tests
  9. Conventions: Follow StyleCop rules, use primary constructors

Built with ❀️ using .NET 10 and Clean Architecture

About

Boilerplate to start a new .net microservice project

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages