Skip to content

nanotaboada/Dotnet.Samples.AspNetCore.WebApi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

839 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

πŸ§ͺ RESTful API with .NET and ASP.NET Core

.NET CI .NET CD CodeQL Quality Gate Status codecov CodeFactor License: MIT Dependabot Copilot Claude CodeRabbit

Proof of Concept for a RESTful API built with .NET 10 (LTS) and ASP.NET Core. Manage football player data with SQLite, Entity Framework Core, Swagger documentation, and in-memory caching.

Table of Contents

Features

  • πŸ—οΈ Clean layered architecture - Repository pattern, dependency injection, and async operations throughout
  • πŸ“š Interactive API exploration - Swagger UI documentation with health monitoring endpoints
  • ⚑ Performance optimizations - In-memory caching, rate limiting, and efficient database queries
  • πŸ§ͺ High test coverage - xUnit tests with automated reporting to Codecov and SonarCloud
  • πŸ“– Token-efficient documentation - Custom instructions with coding guidelines, architecture rules, and agent workflows for AI-assisted development
  • 🐳 Full containerization - Multi-stage Docker builds with Docker Compose orchestration
  • πŸ”„ Complete CI/CD pipeline - Automated testing, code quality checks, Docker publishing, and GitHub releases
  • 🏟️ Stadium-themed semantic versioning - Memorable, alphabetical release names from World Cup venues

Tech Stack

Category Technology
Framework .NET 10 (LTS)
Web Framework ASP.NET Core 10.0
API Documentation Swashbuckle (OpenAPI 3.0)
Validation FluentValidation 12
Mapping AutoMapper 14
Database SQLite 3
ORM Entity Framework Core 10.0
Logging Serilog 9
Testing xUnit, Moq, FluentAssertions
Containerization Docker & Docker Compose

Project Structure

src/Dotnet.Samples.AspNetCore.WebApi/
β”œβ”€β”€ Program.cs                  # Entry point: DI setup, middleware pipeline
β”œβ”€β”€ Controllers/                # HTTP handlers (request/response logic)
β”‚   └── PlayerController.cs
β”œβ”€β”€ Services/                   # Business logic + caching layer
β”‚   β”œβ”€β”€ IPlayerService.cs
β”‚   └── PlayerService.cs
β”œβ”€β”€ Repositories/               # Data access abstraction
β”‚   β”œβ”€β”€ IPlayerRepository.cs
β”‚   β”œβ”€β”€ IRepository.cs
β”‚   β”œβ”€β”€ PlayerRepository.cs
β”‚   └── Repository.cs
β”œβ”€β”€ Models/                     # Domain entities and DTOs
β”‚   β”œβ”€β”€ Player.cs
β”‚   β”œβ”€β”€ PlayerRequestModel.cs
β”‚   └── PlayerResponseModel.cs
β”œβ”€β”€ Data/                       # EF Core DbContext and migrations
β”‚   └── PlayerDbContext.cs
β”œβ”€β”€ Mappings/                   # AutoMapper profiles
β”‚   └── PlayerMappingProfile.cs
β”œβ”€β”€ Validators/                 # FluentValidation rules
β”‚   └── PlayerRequestModelValidator.cs
β”œβ”€β”€ Configurations/             # Swagger, rate limiting config
β”œβ”€β”€ Enums/                      # Domain enumerations (e.g. Position)
β”œβ”€β”€ Extensions/                 # Service registration extensions
β”œβ”€β”€ Middlewares/                # Custom ASP.NET Core middleware
β”œβ”€β”€ Utilities/                  # Helper classes
β”œβ”€β”€ Migrations/                 # EF Core migrations
└── storage/                    # Pre-seeded SQLite database

test/Dotnet.Samples.AspNetCore.WebApi.Tests/
β”œβ”€β”€ Unit/                       # Unit tests with xUnit
β”‚   β”œβ”€β”€ PlayerControllerTests.cs
β”‚   β”œβ”€β”€ PlayerServiceTests.cs
β”‚   └── PlayerValidatorTests.cs
└── Utilities/                  # Shared test helpers
    β”œβ”€β”€ DatabaseFakes.cs
    β”œβ”€β”€ PlayerFakes.cs
    β”œβ”€β”€ PlayerMocks.cs
    └── PlayerStubs.cs

Architecture

Layered architecture with dependency injection via constructors and interface-based contracts.

%%{init: {
  "theme": "default",
  "themeVariables": {
    "fontFamily": "Fira Code, Consolas, monospace",
    "textColor": "#555",
    "lineColor": "#555",
    "clusterBkg": "#f5f5f5",
    "clusterBorder": "#ddd"
  }
}}%%

graph RL

    Tests[Tests]

    subgraph Layer1[" "]
        Program[Program]
        Serilog[Serilog]
        Swashbuckle[Swashbuckle]
    end

    subgraph Layer2[" "]
        Controllers[Controllers]
        Validators[Validators]
        FluentValidation[FluentValidation]
        AspNetCore[ASP.NET Core]
    end

    subgraph Layer3[" "]
        Services[Services]
        Mappings[Mappings]
        AutoMapper[AutoMapper]
        MemoryCache[MemoryCache]
    end

    subgraph Layer4[" "]
        Repositories[Repositories]
        Data[Data]
        EFCore[EF Core]
    end

    Models[Models]

    %% Strong dependencies

    %% Layer 1
    Controllers --> Program
    Serilog --> Program
    Swashbuckle --> Program

    %% Layer 2
    Services --> Controllers
    Validators --> Controllers
    FluentValidation --> Validators
    AspNetCore --> Controllers

    %% Layer 3
    Repositories --> Services
    MemoryCache --> Services
    Mappings --> Services
    AutoMapper --> Mappings
    Models --> Mappings

    %% Layer 4
    Models --> Repositories
    Models --> Data
    Data --> Repositories
    EFCore --> Data
    EFCore -.-> Repositories

    %% Soft dependencies

    Services -.-> Tests
    Controllers -.-> Tests

    %% Node styling with stroke-width
    classDef core fill:#b3d9ff,stroke:#6db1ff,stroke-width:2px,color:#555,font-family:monospace;
    classDef deps fill:#ffcccc,stroke:#ff8f8f,stroke-width:2px,color:#555,font-family:monospace;
    classDef test fill:#ccffcc,stroke:#53c45e,stroke-width:2px,color:#555,font-family:monospace;
    classDef feat fill:#ffffcc,stroke:#fdce15,stroke-width:2px,color:#555,font-family:monospace;

    class Data,Models,Repositories,Services,Controllers,Program,Validators,Mappings core;
    class AutoMapper,FluentValidation,Serilog,Swashbuckle deps;
    class Tests test;
    class AspNetCore,EFCore,MemoryCache feat;
Loading

Arrow Semantics

Arrows follow the injection direction: A --> B means A is injected into B. Solid arrows (-->) represent active ASP.NET Core dependencies β€” services registered with the IoC container and invoked at runtime. Dotted arrows (-.->) represent test dependencies β€” test classes reference the types they exercise but are not injected into them.

Composition Root Pattern

Program is the composition root: it registers all services, repositories, DbContext, mappers, validators, and middleware with the ASP.NET Core IoC container, which resolves them at runtime via constructor injection.

Layered Architecture

Four layers: Initialization (Program), HTTP (Controllers, Validators), Business (Services, Mappings), and Data (Repositories, Data).

Framework and third-party packages are placed inside the subgraph of the layer that uses them β€” Serilog and Swashbuckle in Initialization, ASP.NET Core and FluentValidation in HTTP, AutoMapper in Business, EF Core in Data.

Models is a cross-cutting type concern β€” shared entities and DTOs consumed across all layers, with no logic of its own.

Color Coding

Blue = core application packages, yellow = Microsoft platform packages, red = third-party libraries, green = tests.

Simplified, conceptual view β€” not all components or dependencies are shown.

Architecture Decisions

See Architecture Decision Records (ADRs) for documented decisions about this project's architecture, technology choices, and development practices.

API Reference

Interactive API documentation is available via Swagger UI at https://localhost:9000/swagger/index.html when the server is running.

πŸ’‘ Swagger documentation is only available in development mode for security reasons.

Quick Reference:

  • GET /players - List all players
  • GET /players/{id:Guid} - Get player by ID (requires authentication)
  • GET /players/squadNumber/{squadNumber:int} - Get player by squad number
  • POST /players - Create new player
  • PUT /players/squadNumber/{squadNumber:int} - Update player
  • DELETE /players/squadNumber/{squadNumber:int} - Remove player
  • GET /health - Health check

For complete endpoint documentation with request/response schemas, explore the interactive Swagger UI.

Prerequisites

Before you begin, ensure you have the following installed:

  • .NET 10 SDK (LTS) or higher

  • Docker Desktop (optional, for containerized deployment)

  • dotnet-ef CLI tool (for database migrations)

    dotnet tool install --global dotnet-ef

Quick Start

Clone the repository

git clone https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi.git
cd Dotnet.Samples.AspNetCore.WebApi

Run the application

dotnet watch run --project src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj

The server will start on https://localhost:9000.

Access the application

  • API: https://localhost:9000
  • Swagger Documentation: https://localhost:9000/swagger/index.html
  • Health Check: https://localhost:9000/health

Testing

Run the test suite with xUnit:

# Run all tests
dotnet test

# Run tests with coverage report
dotnet test --results-directory "coverage" --collect:"XPlat Code Coverage" --settings .runsettings

# View coverage report
dotnet tool install --global dotnet-reportgenerator-globaltool
reportgenerator -reports:coverage/**/coverage.cobertura.xml -targetdir:coverage -reporttypes:Html

Tests are located in the test/ directory and use xUnit for unit testing. Coverage reports are generated for controllers and services only.

Containers

This project includes full Docker support with multi-stage builds and Docker Compose for easy deployment.

Build the Docker image

docker compose build

Start the application

docker compose up

πŸ’‘ On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.

Stop the application

docker compose down

Reset the database

To remove the volume and reinitialize the database from the built-in seed file:

docker compose down -v

The containerized application runs on port 9000 and includes health checks that monitor the /health endpoint.

Releases

This project uses stadium-themed release names inspired by famous football stadiums that hosted FIFA World Cup matches. Each release is named after a stadium (A-Z alphabetically), making versions memorable and fun.

Release Naming Convention

Releases follow the pattern: v{SEMVER}-{STADIUM} (e.g., v1.0.0-azteca)

  • Semantic Version: Standard versioning (MAJOR.MINOR.PATCH)
  • Stadium Name: Alphabetically ordered codename from the stadium list

Create a Release

To create a new release, follow this workflow:

1. Update CHANGELOG.md

First, create a release/ branch and document your changes in CHANGELOG.md:

git checkout -b release/1.0.0-azteca
# Move items from [Unreleased] to new release section
# Example: [1.0.0 - azteca] - 2026-01-22
git add CHANGELOG.md
git commit -m "docs: prepare changelog for v1.0.0-azteca release"
git push origin release/1.0.0-azteca
# Open a PR, get it reviewed, and merge into master

2. Create and Push Tag

Then create and push the version tag:

git tag -a v1.0.0-azteca -m "Release 1.0.0 - Azteca"
git push origin v1.0.0-azteca

3. Automated CD Workflow

This triggers the CD workflow which automatically:

  1. Validates the stadium name
  2. Builds and tests the project in Release configuration
  3. Publishes Docker images to GitHub Container Registry with three tags
  4. Creates a GitHub Release with auto-generated changelog from commits

πŸ’‘ Always update CHANGELOG.md before creating the tag. See CHANGELOG.md for detailed release instructions.

Pull Docker Images

Each release publishes multiple tags for flexibility:

# By semantic version (recommended for production)
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:1.0.0

# By stadium name (memorable alternative)
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:azteca

# Latest release
docker pull ghcr.io/nanotaboada/dotnet-samples-aspnetcore-webapi:latest

πŸ’‘ See CHANGELOG.md for the complete stadium list (A-Z) and release history.

Environment Variables

The application can be configured using environment variables for different scenarios:

Local Development (.vscode/launch.json)

For local development and debugging:

# ASP.NET Core environment mode
ASPNETCORE_ENVIRONMENT=Development

# Server URLs
ASPNETCORE_URLS=https://localhost:9000

# Show detailed error messages
ASPNETCORE_DETAILEDERRORS=1

# Graceful shutdown timeout
ASPNETCORE_SHUTDOWNTIMEOUTSECONDS=3

Container Deployment (compose.yaml)

For production deployment:

# Database storage path
# Points to the persistent Docker volume
STORAGE_PATH=/storage/players-sqlite3.db

πŸ’‘ Additional environment variables (ASPNETCORE_ENVIRONMENT=Production and ASPNETCORE_URLS=http://+:9000) are set in the Dockerfile.

Command Summary

Command Description
dotnet watch run --project src/... Start development server with hot reload
dotnet build Build the solution
dotnet test Run all tests
dotnet test --collect:"XPlat Code Coverage" Run tests with coverage report
dotnet csharpier . Format source code
dotnet ef migrations add <Name> Create a new migration
dotnet ef database update Apply migrations
./scripts/run-migrations-and-copy-database.sh Regenerate database with seed data
docker compose build Build Docker image
docker compose up Start Docker container
docker compose down Stop Docker container
docker compose down -v Stop and remove Docker volume

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for details on the code of conduct and the process for submitting pull requests.

Key guidelines:

Legal

This project is provided for educational and demonstration purposes and may be used in production at your own discretion. All trademarks, service marks, product names, company names, and logos referenced herein are the property of their respective owners and are used solely for identification or illustrative purposes.