agentsclimarketplace

Dotnet 10 csharp 14

Skill Harmeet10000/skills/skills/backend/C#_dotnet/dotnet-10-csharp-14

Collection of my Agent Skills and books.

Install
npx -y skills add Harmeet10000/skills --skill dotnet-10-csharp-14

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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

SKILL.md

9.7 KB, as published. Nobody here has run it

.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

FileTopics
csharp-14.mdExtension blocks, field keyword, null-conditional assignment
minimal-apis.mdValidation, TypedResults, filters, modular monolith, vertical slices
security.mdJWT auth, CORS, rate limiting, OpenAPI security, middleware order
infrastructure.mdOptions, resilience, channels, health checks, caching, Serilog, EF Core, keyed services
testing.mdWebApplicationFactory, integration tests, auth testing
anti-patterns.mdHttpClient, DI captive, blocking async, N+1 queries
libraries.mdMediatR, 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 membersC# 14 extension<T>() blocksTraditional this extension methods
Property validationC# 14 field keywordManual backing fields
Null assignmentobj?.Prop = valueif (obj != null) obj.Prop = value
API returnsTypedResults.Ok()Results.Ok()
Options validation.ValidateOnStart()Missing validation
HTTP resilienceAddStandardResilienceHandler()Manual Polly configuration
TimestampsDateTime.UtcNowDateTime.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-PatternFix
new HttpClient()Inject HttpClient or IHttpClientFactory
Results.Ok()TypedResults.Ok()
Manual Polly configAddStandardResilienceHandler()
Singleton → ScopedUse IServiceScopeFactory
GetAsync().Resultawait GetAsync()
Exceptions for flowUse ErrorOr<T> Result pattern
DateTime.NowDateTime.UtcNow
Missing .ValidateOnStart()Always add to Options registration

See anti-patterns.md for complete list.


Libraries Quick Reference

LibraryPackagePurpose
MediatRMediatRCQRS
FluentValidationFluentValidation.DependencyInjectionExtensionsValidation
MapsterMapster.DependencyInjectionMapping
ErrorOrErrorOrResult pattern
PollyMicrosoft.Extensions.Http.ResilienceResilience
SerilogSerilog.AspNetCoreLogging

See libraries.md for usage examples.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.