dotnet-10-csharp-14

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

.NET 10 & C# 14 Best Practices

.NET 10 & C# 14 最佳实践

.NET 10 (LTS, Nov 2025) with C# 14. Covers minimal APIs, not MVC.
Official docs: .NET 10 | C# 14 | ASP.NET Core 10
.NET 10(长期支持版,2025年11月)搭配C# 14。内容涵盖Minimal APIs,不包含MVC。
官方文档: .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

文件主题
csharp-14.md扩展块、
field
关键字、空条件赋值
minimal-apis.md验证、TypedResults、过滤器、模块化单体、垂直切片
security.mdJWT认证、CORS、速率限制、OpenAPI安全、中间件顺序
infrastructure.mdOptions、弹性、Channels、健康检查、缓存、Serilog、EF Core、键控服务
testing.mdWebApplicationFactory、集成测试、认证测试
anti-patterns.mdHttpClient、DI捕获、阻塞异步、N+1查询
libraries.mdMediatR、FluentValidation、Mapster、ErrorOr、Polly、Aspire

Quick Start

快速开始

xml
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <LangVersion>14</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
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();

xml
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <LangVersion>14</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
csharp
var builder = WebApplication.CreateBuilder(args);

// 核心服务
builder.Services.AddValidation();
builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();

// 安全
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddRateLimiter(opts => { /* 详见security.md */ });

// 基础设施
builder.Services.AddHealthChecks();
builder.Services.AddOutputCache();

// 模块
builder.Services.AddUsersModule();

var app = builder.Build();

// 中间件(顺序至关重要 - 详见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

结果 vs 异常

dot
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"];
}
dot
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

IOptions 选择

dot
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"];
}
dot
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

通道类型

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"];
}

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

C# 14 扩展块

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

.NET 10 Built-in Validation

.NET 10 内置验证

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

TypedResults (Always Use)

TypedResults(始终使用)

csharp
app.MapGet("/users/{id}", async (int id, IUserService svc) =>
    await svc.GetAsync(id) is { } user
        ? TypedResults.Ok(user)
        : TypedResults.NotFound());
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<IUserService, UserService>();

    public static IEndpointRouteBuilder MapUsersEndpoints(this IEndpointRouteBuilder app)
    {
        var g = app.MapGroup("/api/users").WithTags("Users");
        g.MapGet("/{id}", GetUser.Handle);
        return app;
    }
}
csharp
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

HTTP 弹性

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

Error Handling (RFC 9457)

错误处理(RFC 9457)

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

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

MANDATORY Patterns (Always Use These)

强制模式(始终使用这些)

Task✅ ALWAYS Use❌ NEVER Use
Extension membersC# 14
extension<T>()
blocks
Traditional
this
extension methods
Property validationC# 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

任务✅ 始终使用❌ 绝不使用
扩展成员C# 14
extension<T>()
传统
this
扩展方法
属性验证C# 14
field
关键字
手动后备字段
空赋值
obj?.Prop = value
if (obj != null) obj.Prop = value
API 返回
TypedResults.Ok()
Results.Ok()
Options 验证
.ValidateOnStart()
缺少验证
HTTP 弹性
AddStandardResilienceHandler()
手动Polly配置
时间戳
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()    │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                    .NET 10 / C# 14 模式                      │
├─────────────────────────────────────────────────────────────────┤
│ 扩展属性:  extension<T>(IEnumerable<T> s) {           │
│                        public bool IsEmpty => !s.Any();         │
│                      }                                          │
├─────────────────────────────────────────────────────────────────┤
│ FIELD 关键字:       public string Name {                       │
│                        get => field;                            │
│                        set => field = value?.Trim();            │
│                      }                                          │
├─────────────────────────────────────────────────────────────────┤
│ OPTIONS 验证:  .BindConfiguration(Section)                │
│                      .ValidateDataAnnotations()                 │
│                      .ValidateOnStart();   // 至关重要!         │
├─────────────────────────────────────────────────────────────────┤
│ HTTP 弹性:     .AddStandardResilienceHandler();           │
├─────────────────────────────────────────────────────────────────┤
│ 类型化结果:       TypedResults.Ok(data)                      │
│                      TypedResults.NotFound()                    │
│                      TypedResults.Created(uri, data)            │
├─────────────────────────────────────────────────────────────────┤
│ 错误模式:       ErrorOr<User> 或 user?.Match(...)          │
├─────────────────────────────────────────────────────────────────┤
│ IOPTIONS:            IOptions<T>        → 启动时加载,不重载    │
│                      IOptionsSnapshot<T> → 每次请求重载   │
│                      IOptionsMonitor<T>  → 实时加载 + OnChange()    │
└─────────────────────────────────────────────────────────────────┘

Anti-Patterns Quick Reference

反模式快速参考

Anti-PatternFix
new HttpClient()
Inject
HttpClient
or
IHttpClientFactory
Results.Ok()
TypedResults.Ok()
Manual Polly config
AddStandardResilienceHandler()
Singleton → ScopedUse
IServiceScopeFactory
GetAsync().Result
await GetAsync()
Exceptions for flowUse
ErrorOr<T>
Result pattern
DateTime.Now
DateTime.UtcNow
Missing
.ValidateOnStart()
Always add to Options registration
See anti-patterns.md for complete list.

反模式修复方案
new HttpClient()
注入
HttpClient
IHttpClientFactory
Results.Ok()
TypedResults.Ok()
手动Polly配置
AddStandardResilienceHandler()
单例→作用域使用
IServiceScopeFactory
GetAsync().Result
await GetAsync()
用异常控制流程使用
ErrorOr<T>
结果模式
DateTime.Now
DateTime.UtcNow
缺少
.ValidateOnStart()
始终在Options注册时添加
详见anti-patterns.md获取完整列表。

Libraries Quick Reference

库快速参考

LibraryPackagePurpose
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.
用途
MediatR
MediatR
CQRS
FluentValidation
FluentValidation.DependencyInjectionExtensions
验证
Mapster
Mapster.DependencyInjection
对象映射
ErrorOr
ErrorOr
结果模式
Polly
Microsoft.Extensions.Http.Resilience
弹性
Serilog
Serilog.AspNetCore
日志
详见libraries.md获取使用示例。