无类型鉴别器时System.Text.Json反序列化嵌套多态对象的问题
问题描述
使用System.Text.Json实现多态类型(抽象基类+派生类)序列化时,框架会自动生成$type类型鉴别器字段用于反序列化。但在Minimal API的Post端点接收客户端请求时,客户端提交的JSON仅包含自定义的枚举标识字段(如TypeAModels、TypeBModels),不含$type,此时直接反序列化抽象基类会抛出System.NotSupportedException异常。
优雅解决方案:自定义JsonConverter
通过实现JsonConverter$type字段,实现自动反序列化。
1. 实现TypeA的自定义转换器
public class TypeAConverter : JsonConverter<TypeA> { public override TypeA? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 先将JSON读入JsonDocument,方便读取枚举字段 using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // 获取TypeAModels枚举值 if (!root.TryGetProperty(nameof(TypeAModels), out var typeProp) || !typeProp.TryGetInt32(out var typeValue)) { throw new JsonException("TypeAModels字段缺失或无效"); } // 根据枚举值选择具体类型反序列化 return (TypeAModels)typeValue switch { TypeAModels.A => JsonSerializer.Deserialize<TypeA_A>(root.GetRawText(), options), TypeAModels.B => JsonSerializer.Deserialize<TypeA_B>(root.GetRawText(), options), _ => throw new JsonException($"不支持的TypeAModels值:{typeValue}") }; } public override void Write(Utf8JsonWriter writer, TypeA value, JsonSerializerOptions options) { // 序列化时直接用默认逻辑,也可自定义输出格式 JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
2. 实现TypeB的自定义转换器
public class TypeBConverter : JsonConverter<TypeB> { public override TypeB? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; if (!root.TryGetProperty(nameof(TypeBModels), out var typeProp) || !typeProp.TryGetInt32(out var typeValue)) { throw new JsonException("TypeBModels字段缺失或无效"); } return (TypeBModels)typeValue switch { TypeBModels.A => JsonSerializer.Deserialize<TypeB_A>(root.GetRawText(), options), TypeBModels.B => JsonSerializer.Deserialize<TypeB_B>(root.GetRawText(), options), _ => throw new JsonException($"不支持的TypeBModels值:{typeValue}") }; } public override void Write(Utf8JsonWriter writer, TypeB value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
3. 在Minimal API中配置转换器
在Program.cs中注册自定义转换器到Json序列化选项:
var builder = WebApplication.CreateBuilder(args); // 配置Json序列化选项,添加自定义转换器 builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.Converters.Add(new TypeAConverter()); options.SerializerOptions.Converters.Add(new TypeBConverter()); }); var app = builder.Build(); // 定义Post端点 app.MapPost("/test", (TypeA typeA) => { // 处理请求逻辑 return Results.Ok(typeA); }); app.Run();
4. 验证效果
客户端提交如下JSON:
{ "Age": 30, "TypeB": { "Year": 1982, "TypeBModels": 1 }, "TypeAModels": 1 }
此时Minimal API会自动将其反序列化为TypeA_A类型,嵌套的TypeB也会被正确反序列化为TypeB_A,无需手动解析JSON字段。
额外优化
- 可将转换器中的重复逻辑(如读取枚举字段)封装为通用方法,减少代码冗余
- 若枚举字段为字符串类型,只需调整为
TryGetString方法即可适配
内容的提问来源于stack exchange,提问作者Roni
相关产品推荐
相关产品推荐

