Skip to content

Commit c15f555

Browse files
Add documentation for Conventions site launch and AI features (#2420)
1 parent 7be87a0 commit c15f555

2,277 files changed

Lines changed: 272146 additions & 4009 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
---
2+
name: dotnet-10-csharp-14
3+
category: developer-experience
4+
subcategory: cli
5+
description: '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'
6+
targets: ['*']
7+
license: MIT
8+
invocable: true
9+
claudecode: {}
10+
opencode: {}
11+
codexcli:
12+
short-description: '.NET skill guidance for dotnet-10-csharp-14'
13+
copilot: {}
14+
geminicli: {}
15+
antigravity: {}
16+
---
17+
18+
# .NET 10 & C# 14 Best Practices
19+
20+
.NET 10 (LTS, Nov 2025) with C# 14. Covers minimal APIs, not MVC.
21+
22+
**Official docs:** [.NET 10](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-10/overview) |
23+
[C# 14](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14) |
24+
[ASP.NET Core 10](https://learn.microsoft.com/en-us/aspnet/core/release-notes/aspnetcore-10.0)
25+
26+
## Detail Files
27+
28+
| File | Topics |
29+
| -------------------------------------- | --------------------------------------------------------------------------------------- |
30+
| [csharp-14.md](csharp-14.md) | Extension blocks, `field` keyword, null-conditional assignment |
31+
| [minimal-apis.md](minimal-apis.md) | Validation, TypedResults, filters, modular monolith, vertical slices |
32+
| [security.md](security.md) | JWT auth, CORS, rate limiting, OpenAPI security, middleware order |
33+
| [infrastructure.md](infrastructure.md) | Options, resilience, channels, health checks, caching, Serilog, EF Core, keyed services |
34+
| [testing.md](testing.md) | WebApplicationFactory, integration tests, auth testing |
35+
| [anti-patterns.md](anti-patterns.md) | HttpClient, DI captive, blocking async, N+1 queries |
36+
| [libraries.md](libraries.md) | MediatR, FluentValidation, Mapster, ErrorOr, Polly, Aspire |
37+
38+
---
39+
40+
## Quick Start
41+
42+
````xml
43+
<Project Sdk="Microsoft.NET.Sdk.Web">
44+
<PropertyGroup>
45+
<TargetFramework>net10.0</TargetFramework>
46+
<LangVersion>14</LangVersion>
47+
<Nullable>enable</Nullable>
48+
</PropertyGroup>
49+
</Project>
50+
```text
51+
52+
```csharp
53+
var builder = WebApplication.CreateBuilder(args);
54+
55+
// Core services
56+
builder.Services.AddValidation();
57+
builder.Services.AddProblemDetails();
58+
builder.Services.AddOpenApi();
59+
60+
// Security
61+
builder.Services.AddAuthentication().AddJwtBearer();
62+
builder.Services.AddAuthorization();
63+
builder.Services.AddRateLimiter(opts => { /* see security.md */ });
64+
65+
// Infrastructure
66+
builder.Services.AddHealthChecks();
67+
builder.Services.AddOutputCache();
68+
69+
// Modules
70+
builder.Services.AddUsersModule();
71+
72+
var app = builder.Build();
73+
74+
// Middleware (ORDER MATTERS - see security.md)
75+
app.UseExceptionHandler();
76+
app.UseHttpsRedirection();
77+
app.UseCors();
78+
app.UseRateLimiter();
79+
app.UseAuthentication();
80+
app.UseAuthorization();
81+
app.UseOutputCache();
82+
83+
app.MapOpenApi();
84+
app.MapHealthChecks("/health");
85+
app.MapUsersEndpoints();
86+
app.Run();
87+
```text
88+
89+
---
90+
91+
## Decision Flowcharts
92+
93+
### Result vs Exception
94+
95+
```dot
96+
digraph {
97+
"Error type?" [shape=diamond];
98+
"Expected?" [shape=diamond];
99+
"Result<T>/ErrorOr" [shape=box];
100+
"Exception" [shape=box];
101+
"Error type?" -> "Expected?" [label="domain"];
102+
"Error type?" -> "Exception" [label="infrastructure"];
103+
"Expected?" -> "Result<T>/ErrorOr" [label="yes"];
104+
"Expected?" -> "Exception" [label="no"];
105+
}
106+
```text
107+
108+
### IOptions Selection
109+
110+
```dot
111+
digraph {
112+
"Runtime changes?" [shape=diamond];
113+
"Per-request?" [shape=diamond];
114+
"IOptions<T>" [shape=box];
115+
"IOptionsSnapshot<T>" [shape=box];
116+
"IOptionsMonitor<T>" [shape=box];
117+
"Runtime changes?" -> "IOptions<T>" [label="no"];
118+
"Runtime changes?" -> "Per-request?" [label="yes"];
119+
"Per-request?" -> "IOptionsSnapshot<T>" [label="yes"];
120+
"Per-request?" -> "IOptionsMonitor<T>" [label="no"];
121+
}
122+
```text
123+
124+
### Channel Type
125+
126+
```dot
127+
digraph {
128+
"Trust producer?" [shape=diamond];
129+
"Can drop?" [shape=diamond];
130+
"Bounded+Wait" [shape=box,style=filled,fillcolor=lightgreen];
131+
"Bounded+Drop" [shape=box];
132+
"Unbounded" [shape=box];
133+
"Trust producer?" -> "Unbounded" [label="yes"];
134+
"Trust producer?" -> "Can drop?" [label="no"];
135+
"Can drop?" -> "Bounded+Drop" [label="yes"];
136+
"Can drop?" -> "Bounded+Wait" [label="no"];
137+
}
138+
```text
139+
140+
---
141+
142+
## Key Patterns Summary
143+
144+
### C# 14 Extension Blocks
145+
146+
```csharp
147+
extension<T>(IEnumerable<T> source)
148+
{
149+
public bool IsEmpty => !source.Any();
150+
}
151+
```text
152+
153+
### .NET 10 Built-in Validation
154+
155+
```csharp
156+
builder.Services.AddValidation();
157+
app.MapPost("/users", (UserDto dto) => TypedResults.Ok(dto));
158+
```text
159+
160+
### TypedResults (Always Use)
161+
162+
```csharp
163+
app.MapGet("/users/{id}", async (int id, IUserService svc) =>
164+
await svc.GetAsync(id) is { } user
165+
? TypedResults.Ok(user)
166+
: TypedResults.NotFound());
167+
```text
168+
169+
### Module Pattern
170+
171+
```csharp
172+
public static class UsersModule
173+
{
174+
public static IServiceCollection AddUsersModule(this IServiceCollection s) => s
175+
.AddScoped<IUserService, UserService>();
176+
177+
public static IEndpointRouteBuilder MapUsersEndpoints(this IEndpointRouteBuilder app)
178+
{
179+
var g = app.MapGroup("/api/users").WithTags("Users");
180+
g.MapGet("/{id}", GetUser.Handle);
181+
return app;
182+
}
183+
}
184+
```text
185+
186+
### HTTP Resilience
187+
188+
```csharp
189+
builder.Services.AddHttpClient<IApi, ApiClient>()
190+
.AddStandardResilienceHandler();
191+
```text
192+
193+
### Error Handling (RFC 9457)
194+
195+
```csharp
196+
builder.Services.AddProblemDetails();
197+
app.UseExceptionHandler();
198+
app.UseStatusCodePages();
199+
```text
200+
201+
---
202+
203+
## MANDATORY Patterns (Always Use These)
204+
205+
| Task | ✅ ALWAYS Use | ❌ NEVER Use |
206+
| ------------------- | -------------------------------- | ------------------------------------ |
207+
| Extension members | C# 14 `extension<T>()` blocks | Traditional `this` extension methods |
208+
| Property validation | C# 14 `field` keyword | Manual backing fields |
209+
| Null assignment | `obj?.Prop = value` | `if (obj != null) obj.Prop = value` |
210+
| API returns | `TypedResults.Ok()` | `Results.Ok()` |
211+
| Options validation | `.ValidateOnStart()` | Missing validation |
212+
| HTTP resilience | `AddStandardResilienceHandler()` | Manual Polly configuration |
213+
| Timestamps | `DateTime.UtcNow` | `DateTime.Now` |
214+
215+
---
216+
217+
## Quick Reference Card
218+
219+
```text
220+
┌─────────────────────────────────────────────────────────────────┐
221+
│ .NET 10 / C# 14 PATTERNS │
222+
├─────────────────────────────────────────────────────────────────┤
223+
│ EXTENSION PROPERTY: extension<T>(IEnumerable<T> s) { │
224+
│ public bool IsEmpty => !s.Any(); │
225+
│ } │
226+
├─────────────────────────────────────────────────────────────────┤
227+
│ FIELD KEYWORD: public string Name { │
228+
│ get => field; │
229+
│ set => field = value?.Trim(); │
230+
│ } │
231+
├─────────────────────────────────────────────────────────────────┤
232+
│ OPTIONS VALIDATION: .BindConfiguration(Section) │
233+
│ .ValidateDataAnnotations() │
234+
│ .ValidateOnStart(); // CRITICAL! │
235+
├─────────────────────────────────────────────────────────────────┤
236+
│ HTTP RESILIENCE: .AddStandardResilienceHandler(); │
237+
├─────────────────────────────────────────────────────────────────┤
238+
│ TYPED RESULTS: TypedResults.Ok(data) │
239+
│ TypedResults.NotFound() │
240+
│ TypedResults.Created(uri, data) │
241+
├─────────────────────────────────────────────────────────────────┤
242+
│ ERROR PATTERN: ErrorOr<User> or user?.Match(...) │
243+
├─────────────────────────────────────────────────────────────────┤
244+
│ IOPTIONS: IOptions<T> → startup, no reload │
245+
│ IOptionsSnapshot<T> → per-request reload │
246+
│ IOptionsMonitor<T> → live + OnChange() │
247+
└─────────────────────────────────────────────────────────────────┘
248+
```text
249+
250+
---
251+
252+
## Anti-Patterns Quick Reference
253+
254+
| Anti-Pattern | Fix |
255+
| ---------------------------- | ------------------------------------------- |
256+
| `new HttpClient()` | Inject `HttpClient` or `IHttpClientFactory` |
257+
| `Results.Ok()` | `TypedResults.Ok()` |
258+
| Manual Polly config | `AddStandardResilienceHandler()` |
259+
| Singleton → Scoped | Use `IServiceScopeFactory` |
260+
| `GetAsync().Result` | `await GetAsync()` |
261+
| Exceptions for flow | Use `ErrorOr<T>` Result pattern |
262+
| `DateTime.Now` | `DateTime.UtcNow` |
263+
| Missing `.ValidateOnStart()` | Always add to Options registration |
264+
265+
See [anti-patterns.md](anti-patterns.md) for complete list.
266+
267+
---
268+
269+
270+
271+
## Code Navigation (Serena MCP)
272+
273+
**Primary approach:** Use Serena symbol operations for efficient code navigation:
274+
275+
1. **Find definitions**: `serena_find_symbol` instead of text search
276+
2. **Understand structure**: `serena_get_symbols_overview` for file organization
277+
3. **Track references**: `serena_find_referencing_symbols` for impact analysis
278+
4. **Precise edits**: `serena_replace_symbol_body` for clean modifications
279+
280+
**When to use Serena vs traditional tools:**
281+
- ✅ **Use Serena**: Navigation, refactoring, dependency analysis, precise edits
282+
- ✅ **Use Read/Grep**: Reading full files, pattern matching, simple text operations
283+
- ✅ **Fallback**: If Serena unavailable, traditional tools work fine
284+
285+
**Example workflow:**
286+
```text
287+
# Instead of:
288+
Read: src/Services/OrderService.cs
289+
Grep: "public void ProcessOrder"
290+
291+
# Use:
292+
serena_find_symbol: "OrderService/ProcessOrder"
293+
serena_get_symbols_overview: "src/Services/OrderService.cs"
294+
```
295+
## Libraries Quick Reference
296+
297+
| Library | Package | Purpose |
298+
| ---------------- | ------------------------------------------------ | -------------- |
299+
| MediatR | `MediatR` | CQRS |
300+
| FluentValidation | `FluentValidation.DependencyInjectionExtensions` | Validation |
301+
| Mapster | `Mapster.DependencyInjection` | Mapping |
302+
| ErrorOr | `ErrorOr` | Result pattern |
303+
| Polly | `Microsoft.Extensions.Http.Resilience` | Resilience |
304+
| Serilog | `Serilog.AspNetCore` | Logging |
305+
306+
See [libraries.md](libraries.md) for usage examples.
307+
````

0 commit comments

Comments
 (0)