MapStaticAssets、HybridCache、SignalR 改进、OpenAPI 增强——ASP.NET Core 9 让 Web 开发更高效
版本定位
适用版本:.NET 9 | ASP.NET Core 9 前置知识:ASP.NET Core 8 基础
背景
ASP.NET Core 9 在 .NET 8 的基础上继续改进,重点是静态资源优化、统一缓存、SignalR 实时通信和可观测性。MapStaticAssets 让静态资源交付自动优化,HybridCache 统一了内存与分布式缓存的编程模型,SignalR 带来了批量发送和更可靠的重连机制。
新特性一览
| 特性 | 简述 | 实用性 |
|---|---|---|
| MapStaticAssets | 构建时压缩、内容指纹 | ⭐⭐⭐⭐⭐ |
| HybridCache | L1 内存 + L2 分布式统一缓存 API | ⭐⭐⭐⭐⭐ |
| SignalR 批量发送 | 合并消息减少网络开销 | ⭐⭐⭐⭐⭐ |
| SignalR 重连改进 | 更可靠的自动重连机制 | ⭐⭐⭐⭐ |
| 请求超时中间件 | 全局请求超时控制 | ⭐⭐⭐⭐ |
| OpenAPI 改进 | 更好的 API 文档生成 | ⭐⭐⭐⭐ |
| 终端日志改进 | 更好的日志输出 | ⭐⭐⭐⭐ |
| JSON 序列化改进 | camelCase 默认、WebDefaults | ⭐⭐⭐⭐ |
| PAR 支持 | Pushed Authorization Request | ⭐⭐⭐⭐ |
| Keyed DI | 按键注册/解析依赖 | ⭐⭐⭐⭐ |
| 开发者异常页面改进 | 更友好的错误调试 | ⭐⭐⭐ |
| Minimal API 改进 | 参数绑定、端点增强 | ⭐⭐⭐ |
| IAsyncEnumerable 改进 | 流式数据处理优化 | ⭐⭐⭐ |
| 健康检查改进 | 更灵活的健康检查 | ⭐⭐⭐ |
| .NET MAUI Blazor Hybrid | 原生 + Web 混合应用 | ⭐⭐⭐ |
特性详解
1. MapStaticAssets
之前的做法:使用 UseStaticFiles
// ASP.NET Core 8 及之前 app.UseStaticFiles();
ASP.NET Core 9 的做法:使用 MapStaticAssets
// ASP.NET Core 9 app.MapStaticAssets();
优势:
| 特性 | UseStaticFiles | MapStaticAssets |
|---|---|---|
| 压缩 | 运行时压缩 | 构建时压缩 |
| 缓存 | 手动配置 | 自动配置 |
| 指纹 | 无 | 内容指纹 |
| 大小 | 原始大小 | 压缩后大小 |
内容指纹:
浏览器会缓存文件,直到指纹变化才会重新下载。
2. HybridCache 统一缓存 API
之前的做法:需要同时管理 IMemoryCache 和 IDistributedCache
// ASP.NET Core 8 及之前
builder.Services.AddMemoryCache();
builder.Services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost:6379";
});
// 使用时需要手动处理 L1/L2 逻辑
public class ProductService
{
private readonly IMemoryCache _memoryCache;
private readonly IDistributedCache _distributedCache;
public async Task GetProductAsync(int id)
{
// L1: 内存缓存
if (_memoryCache.TryGetValue($"product:{id}", out Product? cached))
return cached;
// L2: 分布式缓存
var json = await _distributedCache.GetStringAsync($"product:{id}");
if (json != null)
{
var product = JsonSerializer.Deserialize(json);
_memoryCache.Set($"product:{id}", product, TimeSpan.FromMinutes(5));
return product;
}
// 数据库查询
var dbProduct = await _dbContext.Products.FindAsync(id);
if (dbProduct != null)
{
await _distributedCache.SetStringAsync($"product:{id}",
JsonSerializer.Serialize(dbProduct));
_memoryCache.Set($"product:{id}", dbProduct, TimeSpan.FromMinutes(5));
}
return dbProduct;
}
}
ASP.NET Core 9 的做法:HybridCache 统一 API
// 注册 HybridCache
builder.Services.AddHybridCache();
// 或自定义配置
builder.Services.AddHybridCache(options =>
{
options.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(2)
};
});
// 使用
public class ProductService
{
private readonly HybridCache _cache;
public ProductService(HybridCache cache)
{
_cache = cache;
}
public async Task GetProductAsync(int id)
{
return await _cache.GetOrCreateAsync(
$"product:{id}",
async ct => await _dbContext.Products.FindAsync(id, ct),
new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10)
});
}
}
对比:
| 特性 | 手动管理 L1/L2 | HybridCache |
|---|---|---|
| 代码量 | 多(~30 行) | 少(~5 行) |
| Stampede 保护 | 需自行实现 | 内置 |
| 多节点一致性 | 需自行实现 | 自动 |
| 取消令牌支持 | 需手动传递 | 内置 |
Stampede 保护:当多个请求同时请求同一个缓存键时,HybridCache 只会执行一次数据库查询,其他请求等待结果:
// 100 个并发请求同时访问 product:1 // HybridCache 只执行 1 次数据库查询,其余 99 个请求共享结果 var tasks = Enumerable.Range(0, 100) .Select(_ => service.GetProductAsync(1)); await Task.WhenAll(tasks);
3. SignalR 批量发送
之前的做法:每条消息单独发送
// ASP.NET Core 8 及之前 // 100 条消息 = 100 次网络往返 for (int i = 0; i
ASP.NET Core 9 的做法:批量发送
// 配置批量发送
builder.Services.AddSignalR(options =>
{
options.EnableBatching = true;
options.MaximumReceiveMessageSize = 32 * 1024; // 32KB
});
对比:
| 指标 | 无批量 | 有批量 |
|---|---|---|
| 100 条消息网络往返 | 100 次 | 1-5 次 |
| 延迟 | 高 | 低 |
| 吞吐量 | 低 | 高 |
4. SignalR 重连改进
之前的做法:默认重连策略较简单
ASP.NET Core 9 的做法:更可靠的重连机制
// 客户端配置
var connection = new HubConnectionBuilder()
.WithUrl("/chathub")
.WithAutomaticReconnect(new[]
{
TimeSpan.FromSeconds(0), // 首次立即重连
TimeSpan.FromSeconds(2), // 2 秒后
TimeSpan.FromSeconds(5), // 5 秒后
TimeSpan.FromSeconds(10), // 10 秒后
TimeSpan.FromSeconds(30) // 30 秒后
})
.Build();
// 重连事件
connection.Reconnecting += error =>
{
Console.WriteLine($"连接断开,正在重连... 原因: {error?.Message}");
return Task.CompletedTask;
};
connection.Reconnected += connectionId =>
{
Console.WriteLine($"重连成功,新 ConnectionId: {connectionId}");
return Task.CompletedTask;
};
5. 请求超时中间件
// 注册请求超时中间件
builder.Services.AddRequestTimeouts();
var app = builder.Build();
// 全局超时(默认 30 秒)
app.UseRequestTimeouts();
// 端点级超时
app.MapGet("/slow", async (HttpContext context) =>
{
await Task.Delay(60_000, context.RequestAborted);
return "Done";
}).WithRequestTimeout(TimeSpan.FromSeconds(10));
// 自定义超时响应
app.UseRequestTimeouts(new RequestTimeoutOptions
{
DefaultTimeout = TimeSpan.FromSeconds(15),
TimeoutStatusCode = 408,
WriteTimeoutResponse = async (context, token) =>
{
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(
JsonSerializer.Serialize(new { error = "请求超时" }), token);
}
});
6. OpenAPI 改进
// ASP.NET Core 9
builder.Services.AddOpenApi();
var app = builder.Build();
// 自动生成 OpenAPI 文档
app.MapOpenApi("/openapi/{documentName}.json");
// 使用 Scalar 替代 Swagger UI
app.MapScalarApiReference();
改进点:
- 更好的 Schema 生成
- 支持更复杂的类型
- 更准确的文档
- 内置 Scalar UI 支持
7. JSON 序列化改进
// ASP.NET Core 9:默认 camelCase
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// WebDefaults 预配置
builder.Services.ConfigureHttpJsonOptions(options =>
{
// 使用 Web 开发推荐的默认设置
options.SerializerOptions.WebDefaults(); // 新 API
});
// 枚举序列化为字符串
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
8. PAR(Pushed Authorization Request)支持
// 配置 PAR
builder.Services.AddAuthentication()
.AddOpenIdConnect(options =>
{
options.Authority = "https://identity.example.com";
options.ClientId = "my-app";
options.ResponseType = "code";
// 启用 PAR
options.PushedAuthorization = new OpenIdConnectOptionsPushedAuthorization
{
RequirePushedAuthorization = true,
PushedAuthorizationLifetime = TimeSpan.FromMinutes(10)
};
});
// 优势:
// 1. 防止授权请求被篡改
// 2. 支持大型请求参数
// 3. 更安全的 OAuth 2.0 流程
9. Keyed DI 依赖注入
// ASP.NET Core 9:按键注册服务
builder.Services.AddKeyedSingleton("memory");
builder.Services.AddKeyedSingleton("redis");
builder.Services.AddKeyedSingleton("kafka");
builder.Services.AddKeyedSingleton("rabbitmq");
// 解析时指定键
app.MapGet("/cache/memory", ([FromKeyedServices("memory")] ICache cache) =>
{
return cache.Get("key");
});
app.MapGet("/cache/redis", ([FromKeyedServices("redis")] ICache cache) =>
{
return cache.Get("key");
});
// 构造函数注入
public class MyService
{
private readonly ICache _memoryCache;
private readonly ICache _redisCache;
public MyService(
[FromKeyedServices("memory")] ICache memoryCache,
[FromKeyedServices("redis")] ICache redisCache)
{
_memoryCache = memoryCache;
_redisCache = redisCache;
}
}
10. 终端日志改进
builder.Logging.AddJsonConsole(options =>
{
options.IncludeScopes = true;
options.TimestampFormat = "yyyy-MM-dd HH:mm:ss";
options.JsonWriterOptions = new JsonWriterOptions
{
Indented = true
};
});
11. 开发者异常页面改进
// ASP.NET Core 9
builder.Services.AddDeveloperExceptionPage(options =>
{
// 自定义异常页面内容
options.SourceCodeLineCount = 6; // 显示异常行上下各 6 行代码
});
app.UseDeveloperExceptionPage();
// 新增功能:
// - 更详细的请求/响应信息
// - 中间件管道可视化
// - 异常链完整展示
12. Minimal API 改进
// ASP.NET Core 9:更好的参数绑定
app.MapGet("/users/{id:int}", (int id) => Results.Ok(new { id }));
// 改进的端点元数据
app.MapGet("/products/{id}")
.WithName("GetProduct")
.WithTags("Products")
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status404NotFound)
.WithOpenApi();
// IAsyncEnumerable 改进:更好的流式支持
app.MapGet("/stream", async (HttpContext context) =>
{
var channel = Channel.CreateUnbounded();
// 后台任务持续写入
_ = Task.Run(async () =>
{
for (int i = 0; i
13. 健康检查改进
// ASP.NET Core 9:更灵活的健康检查
builder.Services.AddHealthChecks()
.AddCheck("database", () =>
{
// 检查数据库连接
try
{
using var conn = new SqlConnection(connectionString);
conn.Open();
return HealthCheckResult.Healthy("数据库连接正常");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("数据库连接异常", ex);
}
})
.AddCheck("redis", () =>
{
// 检查 Redis 连接
return HealthCheckResult.Healthy("Redis 连接正常");
});
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
14. .NET MAUI Blazor Hybrid
// 创建混合应用 builder.Services.AddMauiBlazorWebView(); // 在 Razor 组件中使用 @page "/"Hello, MAUI Blazor!
@code { void OpenNativeDialog() { DisplayAlert("提示", "这是一个原生对话框", "确定"); } }
实战场景
HybridCache 适合的场景
- 高频读取的配置数据:数据库配置 → HybridCache 自动管理 L1/L2
- 电商商品查询:热门商品缓存在内存,冷门商品缓存在 Redis
- API 响应缓存:统一缓存策略,减少数据库压力
SignalR 批量发送适合的场景
- 实时仪表板:大量指标数据需要实时推送
- 聊天应用:消息量大时自动批量发送
- 游戏服务器:高频状态同步
Keyed DI 适合的场景
- 多数据库支持:同一接口不同实现
- 多消息队列:Kafka + RabbitMQ 并存
- 多缓存策略:内存缓存 + Redis 缓存
迁移建议
从 ASP.NET Core 8 升级
# 1. 更新 SDK
dotnet --list-sdks
# 2. 更新项目文件
net9.0
# 3. 更新 NuGet 包
dotnet list package --outdated
# 4. 替换 UseStaticFiles
# app.UseStaticFiles();
app.MapStaticAssets();
# 5. 添加 HybridCache
builder.Services.AddHybridCache();
# 6. 配置 SignalR 批量发送
builder.Services.AddSignalR(options =>
{
options.EnableBatching = true;
});
注意事项
- MapStaticAssets:只适用于已知的静态资源
- HybridCache:需要配置分布式缓存(Redis 等)
- SignalR 批量发送:可能增加少量延迟,但减少网络往返
- Keyed DI:需要 .NET 9+ SDK
一句话总结
ASP.NET Core 9 让 Web 开发更高效:MapStaticAssets 优化静态资源、HybridCache 统一缓存、SignalR 批量发送提升实时性能。
官方文档
📦 示例代码:.NET 新特性巡礼全系列配套示例代码(含 dotnet 8/9/10)
- GitHub:GitHub – LadyKiller1025/dotnet-feature-tour-demos: .NET Feature Tour – Code Demos (.NET 8/9/10) · GitHub
- Gitee:https://gitee.com/qakjhzx/dotnet-feature-tour-demos
到此这篇关于ASP.NET Core 9 新特性全面解析的文章就介绍到这了,更多相关asp.net core新特征内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!
