🎯

dotnet-10-csharp-14

🎯Skill

from mhagrelius/dotfiles

VibeIndex|
What it does

Modernizes .NET development with C# 14 best practices, minimal APIs, modular architecture, and advanced infrastructure patterns.

dotnet-10-csharp-14

Installation

Install skill:
npx skills add https://github.com/mhagrelius/dotfiles --skill dotnet-10-csharp-14
29
Last UpdatedJan 21, 2026

Skill Details

SKILL.md

Use when building .NET 10 or C# 14 applications; when using minimal APIs, modular monolith patterns, or feature folders; when implementing HTTP resilience, Options pattern, Channels, or validation; when seeing outdated patterns like old extension method syntax

Overview

# .NET 10 & C# 14 Best Practices

.NET 10 (LTS, Nov 2025) with C# 14. Covers minimal APIs, not MVC.

Official docs: [.NET 10](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview) | [C# 14](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14) | [ASP.NET Core 10](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-10.0)

Detail Files

| File | Topics |

|------|--------|

| [csharp-14.md](csharp-14.md) | Extension blocks, field keyword, null-conditional assignment |

| [minimal-apis.md](minimal-apis.md) | Validation, TypedResults, filters, modular monolith, vertical slices |

| [security.md](security.md) | JWT auth, CORS, rate limiting, OpenAPI security, middleware order |

| [infrastructure.md](infrastructure.md) | Options, resilience, channels, health checks, caching, Serilog, EF Core, keyed services |

| [testing.md](testing.md) | WebApplicationFactory, integration tests, auth testing |

| [anti-patterns.md](anti-patterns.md) | HttpClient, DI captive, blocking async, N+1 queries |

| [libraries.md](libraries.md) | MediatR, FluentValidation, Mapster, ErrorOr, Polly, Aspire |

---

Quick Start

```xml

net10.0

14

enable

```

```csharp

var builder = WebApplication.CreateBuilder(args);

// Core services

builder.Services.AddValidation();

builder.Services.AddProblemDetails();

builder.Services.AddOpenApi();

// Security

builder.Services.AddAuthentication().AddJwtBearer();

builder.Services.AddAuthorization();

builder.Services.AddRateLimiter(opts => { / see security.md / });

// Infrastructure

builder.Services.AddHealthChecks();

builder.Services.AddOutputCache();

// Modules

builder.Services.AddUsersModule();

var app = builder.Build();

// Middleware (ORDER MATTERS - see security.md)

app.UseExceptionHandler();

app.UseHttpsRedirection();

app.UseCors();

app.UseRateLimiter();

app.UseAuthentication();

app.UseAuthorization();

app.UseOutputCache();

app.MapOpenApi();

app.MapHealthChecks("/health");

app.MapUsersEndpoints();

app.Run();

```

---

Decision Flowcharts

Result vs Exception

```dot

digraph {

"Error type?" [shape=diamond];

"Expected?" [shape=diamond];

"Result/ErrorOr" [shape=box];

"Exception" [shape=box];

"Error type?" -> "Expected?" [label="domain"];

"Error type?" -> "Exception" [label="infrastructure"];

"Expected?" -> "Result/ErrorOr" [label="yes"];

"Expected?" -> "Exception" [label="no"];

}

```

IOptions Selection

```dot

digraph {

"Runtime changes?" [shape=diamond];

"Per-request?" [shape=diamond];

"IOptions" [shape=box];

"IOptionsSnapshot" [shape=box];

"IOptionsMonitor" [shape=box];

"Runtime changes?" -> "IOptions" [label="no"];

"Runtime changes?" -> "Per-request?" [label="yes"];

"Per-request?" -> "IOptionsSnapshot" [label="yes"];

"Per-request?" -> "IOptionsMonitor" [label="no"];

}

```

Channel Type

```dot

digraph {

"Trust producer?" [shape=diamond];

"Can drop?" [shape=diamond];

"Bounded+Wait" [shape=box,style=filled,fillcolor=lightgreen];

"Bounded+Drop" [shape=box];

"Unbounded" [shape=box];

"Trust producer?" -> "Unbounded" [label="yes"];

"Trust producer?" -> "Can drop?" [label="no"];

"Can drop?" -> "Bounded+Drop" [label="yes"];

"Can drop?" -> "Bounded+Wait" [label="no"];

}

```

---

Key Patterns Summary

C# 14 Extension Blocks

```csharp

extension(IEnumerable source)

{

public bool IsEmpty => !source.Any();

}

```

.NET 10 Built-in Validation

```csharp

builder.Services.AddValidation();

app.MapPost("/users", (UserDto dto) => TypedResults.Ok(dto));

```

TypedResults (Always Use)

```csharp

app.MapGet("/users/{id}", async (int id, IUserService svc) =>

await svc.GetAsync(id) is { } user

? TypedResults.Ok(user)

: TypedResults.NotFound());

```

Module Pattern

```csharp

public static class UsersModule

{

public static IServiceCollection AddUsersModule(this IServiceCollection s) => s

.AddScoped();

public static IEndpointRouteBuilder MapUsersEndpoints(this IEndpointRouteBuilder app)

{

var g = app.MapGroup("/api/users").WithTags("Users");

g.MapGet("/{id}", GetUser.Handle);

return app;

}

}

```

HTTP Resilience

```csharp

builder.Services.AddHttpClient()

.AddStandardResilienceHandler();

```

Error Handling (RFC 9457)

```csharp

builder.Services.AddProblemDetails();

app.UseExceptionHandler();

app.UseStatusCodePages();

```

---

MANDATORY Patterns (Always Use These)

| Task | βœ… ALWAYS Use | ❌ NEVER Use |

|------|--------------|--------------|

| Extension members | C# 14 extension() blocks | Traditional this extension methods |

| Property validation | C# 14 field keyword | Manual backing fields |

| Null assignment | obj?.Prop = value | if (obj != null) obj.Prop = value |

| API returns | TypedResults.Ok() | Results.Ok() |

| Options validation | .ValidateOnStart() | Missing validation |

| HTTP resilience | AddStandardResilienceHandler() | Manual Polly configuration |

| Timestamps | DateTime.UtcNow | DateTime.Now |

---

Quick Reference Card

```

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ .NET 10 / C# 14 PATTERNS β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ EXTENSION PROPERTY: extension(IEnumerable s) { β”‚

β”‚ public bool IsEmpty => !s.Any(); β”‚

β”‚ } β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ FIELD KEYWORD: public string Name { β”‚

β”‚ get => field; β”‚

β”‚ set => field = value?.Trim(); β”‚

β”‚ } β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ OPTIONS VALIDATION: .BindConfiguration(Section) β”‚

β”‚ .ValidateDataAnnotations() β”‚

β”‚ .ValidateOnStart(); // CRITICAL! β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ HTTP RESILIENCE: .AddStandardResilienceHandler(); β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ TYPED RESULTS: TypedResults.Ok(data) β”‚

β”‚ TypedResults.NotFound() β”‚

β”‚ TypedResults.Created(uri, data) β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ ERROR PATTERN: ErrorOr or user?.Match(...) β”‚

β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

β”‚ IOPTIONS: IOptions β†’ startup, no reload β”‚

β”‚ IOptionsSnapshot β†’ per-request reload β”‚

β”‚ IOptionsMonitor β†’ live + OnChange() β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

```

---

Anti-Patterns Quick Reference

| Anti-Pattern | Fix |

|--------------|-----|

| new HttpClient() | Inject HttpClient or IHttpClientFactory |

| Results.Ok() | TypedResults.Ok() |

| Manual Polly config | AddStandardResilienceHandler() |

| Singleton β†’ Scoped | Use IServiceScopeFactory |

| GetAsync().Result | await GetAsync() |

| Exceptions for flow | Use ErrorOr Result pattern |

| DateTime.Now | DateTime.UtcNow |

| Missing .ValidateOnStart() | Always add to Options registration |

See [anti-patterns.md](anti-patterns.md) for complete list.

---

Libraries Quick Reference

| Library | Package | Purpose |

|---------|---------|---------|

| MediatR | MediatR | CQRS |

| FluentValidation | FluentValidation.DependencyInjectionExtensions | Validation |

| Mapster | Mapster.DependencyInjection | Mapping |

| ErrorOr | ErrorOr | Result pattern |

| Polly | Microsoft.Extensions.Http.Resilience | Resilience |

| Serilog | Serilog.AspNetCore | Logging |

See [libraries.md](libraries.md) for usage examples.

More from this repository8

🎯
working-with-aspire🎯Skill

Helps debug and configure .NET Aspire distributed applications, resolving service discovery, environment, deployment, and polyglot integration challenges.

🎯
using-python-lsp🎯Skill

Enables precise Python code navigation and type checking using pyright-lsp, finding references, definitions, and verifying type correctness semantically.

🎯
building-tui-apps🎯Skill

Builds interactive terminal user interfaces (TUIs) with responsive layouts, keyboard navigation, and real-time data updates across multiple programming languages.

🎯
building-cli-apps🎯Skill

Guides developers in creating robust, Unix-philosophy-aligned command-line interface tools with best practices for argument parsing, stream handling, and cross-language implementation.

🎯
yt-transcribe🎯Skill

Transcribes YouTube video content, extracting spoken text from videos for quick understanding and analysis.

🎯
developing-gtk-apps🎯Skill

Helps developers architect and debug GTK 4/libadwaita applications by addressing lifecycle, threading, resource management, and packaging challenges.

🎯
designing-gnome-ui🎯Skill

Designs GNOME user interfaces with precision, ensuring Human Interface Guidelines compliance and modern libadwaita styling.

🎯
using-typescript-lsp🎯Skill

Enables semantic code intelligence for TypeScript/JavaScript, providing accurate references, type checking, definition navigation, and symbol understanding.