近日,有开发者在 .NET 10 预览版中发现一个影响 Minimal API 验证功能的棘手问题:当请求 DTO(数据传输对象)中包含 System.Text.Json.JsonElement 类型的属性时,使用内置验证(如 AddValidation 或 WithValidation)会触发 "Property 'this[]' not found on type 'JsonElement'" 异常,导致请求无法正常处理。该问题已在 GitHub 上引发社区讨论,微软团队已将其标记为“待确认”。
问题复现场景
该 BUG 在使用 Minimal API 的验证中间件时极易复现。假设定义如下 DTO:
public record CreateUserRequest
{
public string Name { get; set; }
public JsonElement Metadata { get; set; } // 允许接收任意JSON结构
}
并在 Minimal API 端点中启用验证:
app.MapPost("/users", (CreateUserRequest request) => { ... })
.AddValidation();
当客户端发送包含 Metadata 字段的 JSON 请求时,验证中间件在尝试解析请求体时会抛出 InvalidOperationException,错误信息为 "Property 'this[]' not found on type 'JsonElement'"。
经过社区开发者调试,发现异常发生在 System.Text.Json 的序列化与验证框架交互过程中。验证中间件试图对 JsonElement 类型的属性进行递归检查时,错误地调用了索引器 this[] 属性,而 JsonElement 类型并未定义该属性。这种类型映射的缺失导致验证逻辑崩溃。
根因分析:验证框架与 JsonElement 类型的不兼容
JsonElement 是 System.Text.Json 中用于表示任意 JSON 节点的结构体,它本身不提供对子元素的直接索引访问(即 element["key"] 语法实际上是通过 GetProperty 方法实现的),而验证框架在尝试遍历对象属性时,默认假设所有类型都支持 this[] 索引器(即 [int] 或 [string] 索引器属性)。当遇到 JsonElement 这种无索引器的类型时,反射寻找失败,从而抛出异常。
值得注意的是,这种异常并不会在没有验证逻辑的普通 Minimal API 端点中出现——普通的反序列化可以正常将 JSON 映射到 JsonElement 属性。只有启用了验证中间件(如 AddValidation()、WithValidation() 或自定义 ValidationFilter)时才会触发。
对开发者的影响
该 BUG 对使用 .NET 10 预览版构建 API 的开发者影响较为明显,尤其是那些需要接受动态 JSON 数据的场景,例如:
- Webhook 接收器:需要保留原始请求体的某些部分以供后续处理。
- 配置代理:接收并转发任意结构的 JSON 数据。
- 扩展字段:在强类型 DTO 中保留
JsonElement字段以支持未来扩展。
目前,受影响的开发者需要采用以下几种临时方案之一来规避:
- 禁用端点级别的验证:移除
.AddValidation()或.WithValidation(),在业务逻辑中手动执行验证。 - 使用
JsonDocument代替:将 DTO 中的JsonElement改为string类型,并在业务代码中手动解析JsonDocument。 - 自定义 ValidationFilter:编写跳过
JsonElement类型字段的验证逻辑。
微软官方回应与修复预期
该问题已在 .NET 的官方 GitHub 仓库(dotnet/aspnetcore)中提交 Issue,项目维护者已确认存在该行为,并开始调查修复方案。由于 .NET 10 目前处于预览阶段,该问题可能会在后续的预览版或 RC 版本中得到修复。微软方面表示,验证中间件需要对 JsonElement、JsonNode、JsonDocument 等动态类型做特殊处理,避免尝试索引访问。
与此同时,社区也在讨论更根本的解决思路:在验证框架的反射缓存中,对已知的“不可遍历”类型(如原始类型、字符串、流、JsonElement 等)进行白名单过滤,从而避免不必要的属性发现。也有人在建议引入一个 [SkipValidation] 属性,可以标记在属性上以跳过该属性的嵌套验证。
给开发者的建议
对于正在尝试 .NET 10 预览版的开发者,如果在 Minimal API 中使用 JsonElement,建议暂时关闭验证或使用替代方案。如果必须在 DTO 中保留动态数据,可以考虑将 JsonElement 属性标记为 [JsonIgnore] 并在自定义的序列化/反序列化方法中处理,或者等待官方修复。
此外,该问题也提醒我们:在框架预览阶段,对于非主流的类型组合(如 DTO 混合强类型与动态类型)需要谨慎测试。微软在 .NET 10 中大力推广 Minimal API 和一流的验证体验,类似这样的边界情况应该很快得到处理。
随着 .NET 10 的成熟,该 BUG 预计在下一个预览版中得到解决。届时,开发者可以恢复使用 JsonElement 字段,享受 Minimal API 带来的简洁与高效。在此之前,保持对官方 Issue 追踪的关注是明智之举。