dotnet-10-csharp-14

.NET 10 & C# 14 Best Practices

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "dotnet-10-csharp-14" with this command: npx skills add mhagrelius/dotfiles/mhagrelius-dotfiles-dotnet-10-csharp-14

.NET 10 & C# 14 Best Practices

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

Official docs: .NET 10 | C# 14 | ASP.NET Core 10

Detail Files

File Topics

csharp-14.md Extension blocks, field keyword, null-conditional assignment

minimal-apis.md Validation, TypedResults, filters, modular monolith, vertical slices

security.md JWT auth, CORS, rate limiting, OpenAPI security, middleware order

infrastructure.md Options, resilience, channels, health checks, caching, Serilog, EF Core, keyed services

testing.md WebApplicationFactory, integration tests, auth testing

anti-patterns.md HttpClient, DI captive, blocking async, N+1 queries

libraries.md MediatR, FluentValidation, Mapster, ErrorOr, Polly, Aspire

Quick Start

<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net10.0</TargetFramework> <LangVersion>14</LangVersion> <Nullable>enable</Nullable> </PropertyGroup> </Project>

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

digraph { "Error type?" [shape=diamond]; "Expected?" [shape=diamond]; "Result<T>/ErrorOr" [shape=box]; "Exception" [shape=box]; "Error type?" -> "Expected?" [label="domain"]; "Error type?" -> "Exception" [label="infrastructure"]; "Expected?" -> "Result<T>/ErrorOr" [label="yes"]; "Expected?" -> "Exception" [label="no"]; }

IOptions Selection

digraph { "Runtime changes?" [shape=diamond]; "Per-request?" [shape=diamond]; "IOptions<T>" [shape=box]; "IOptionsSnapshot<T>" [shape=box]; "IOptionsMonitor<T>" [shape=box]; "Runtime changes?" -> "IOptions<T>" [label="no"]; "Runtime changes?" -> "Per-request?" [label="yes"]; "Per-request?" -> "IOptionsSnapshot<T>" [label="yes"]; "Per-request?" -> "IOptionsMonitor<T>" [label="no"]; }

Channel Type

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

extension<T>(IEnumerable<T> source) { public bool IsEmpty => !source.Any(); }

.NET 10 Built-in Validation

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

TypedResults (Always Use)

app.MapGet("/users/{id}", async (int id, IUserService svc) => await svc.GetAsync(id) is { } user ? TypedResults.Ok(user) : TypedResults.NotFound());

Module Pattern

public static class UsersModule { public static IServiceCollection AddUsersModule(this IServiceCollection s) => s .AddScoped<IUserService, UserService>();

public static IEndpointRouteBuilder MapUsersEndpoints(this IEndpointRouteBuilder app)
{
    var g = app.MapGroup("/api/users").WithTags("Users");
    g.MapGet("/{id}", GetUser.Handle);
    return app;
}

}

HTTP Resilience

builder.Services.AddHttpClient<IApi, ApiClient>() .AddStandardResilienceHandler();

Error Handling (RFC 9457)

builder.Services.AddProblemDetails(); app.UseExceptionHandler(); app.UseStatusCodePages();

MANDATORY Patterns (Always Use These)

Task ✅ ALWAYS Use ❌ NEVER Use

Extension members C# 14 extension<T>() 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<T>(IEnumerable<T> 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<User> or user?.Match(...) │ ├─────────────────────────────────────────────────────────────────┤ │ IOPTIONS: IOptions<T> → startup, no reload │ │ IOptionsSnapshot<T> → per-request reload │ │ IOptionsMonitor<T> → 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<T> Result pattern

DateTime.Now

DateTime.UtcNow

Missing .ValidateOnStart()

Always add to Options registration

See 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 for usage examples.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

building-tui-apps

No summary provided by upstream source.

Repository SourceNeeds Review
General

working-with-aspire

No summary provided by upstream source.

Repository SourceNeeds Review
General

designing-gnome-ui

No summary provided by upstream source.

Repository SourceNeeds Review