System.Text.Json多态序列化在WebApi控制器中失效问题求助
问题:System.Text.Json在WebAPI返回派生类时不生成类型鉴别器
.NET 7.0发布后,System.Text.Json本应支持多态序列化,但在WebApi控制器方法返回派生类实例时,无法正常生成类型鉴别器。
示例代码
模型定义
public class Base {} public class Derived1: Base { } public class Derived2: Base { }
自定义动态类型信息解析器
public class JsonHierarchyTypeInfoResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var jsonTypeInfo = base.GetTypeInfo(type, options); if( typeof(Base) == jsonTypeInfo.Type ) { jsonTypeInfo.PolymorphismOptions = new( ) { TypeDiscriminatorPropertyName = "$type", IgnoreUnrecognizedTypeDiscriminators = true, UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization, DerivedTypes = { new JsonDerivedType(typeof(Derived1), typeof(Derived1).AssemblyQualifiedName!), new JsonDerivedType(typeof(Derived2), typeof(Derived2).AssemblyQualifiedName!) } }; } return jsonTypeInfo; } }
项目配置
builder.Services.AddControllers( ) .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; options.JsonSerializerOptions.TypeInfoResolver = new JsonHierarchyTypeInfoResolver( ); });
控制器示例
[ApiController] [Route("[controller]")] public class DEMOController : ControllerBase { [HttpGet] public ActionResult<Base> GetAsync() { var derived = new Derived1( ); return Ok(derived); } }
问题原因
这是System.Text.Json在WebAPI场景下的已知行为,并非配置遗漏。SystemTextJsonOutputFormatter序列化时,会根据**实际返回对象的类型(Derived1)**而非控制器方法声明的返回类型(Base)来获取JsonTypeInfo,导致自定义解析器中仅针对Base类型的多态配置没有被触发。
解决方案
方案1:显式指定序列化基类型
在控制器中手动使用基类型序列化对象,再返回JSON内容:
[HttpGet] public IActionResult GetAsync() { var derived = new Derived1(); var json = JsonSerializer.Serialize(derived, typeof(Base), new JsonSerializerOptions { TypeInfoResolver = new JsonHierarchyTypeInfoResolver() }); return Content(json, "application/json"); }
方案2:修改自定义解析器覆盖派生类
调整解析器逻辑,当处理的类型是Base或其派生类时,都应用多态配置:
public class JsonHierarchyTypeInfoResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options) { var jsonTypeInfo = base.GetTypeInfo(type, options); var baseType = typeof(Base); // 匹配基类或所有派生类 if (baseType.IsAssignableFrom(type)) { jsonTypeInfo.PolymorphismOptions = new() { TypeDiscriminatorPropertyName = "$type", IgnoreUnrecognizedTypeDiscriminators = true, UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization, DerivedTypes = { new JsonDerivedType(typeof(Derived1), typeof(Derived1).AssemblyQualifiedName!), new JsonDerivedType(typeof(Derived2), typeof(Derived2).AssemblyQualifiedName!) } }; } return jsonTypeInfo; } }
方案3:自定义输出格式化器
实现自定义格式化器,强制使用控制器声明的返回类型序列化:
public class PolymorphicSystemTextJsonOutputFormatter : SystemTextJsonOutputFormatter { public PolymorphicSystemTextJsonOutputFormatter(JsonSerializerOptions options) : base(options) { } protected override void WriteObject(Utf8JsonWriter writer, object value, Type declaredType) { // 使用声明类型而非实际对象类型序列化 JsonSerializer.Serialize(writer, value, declaredType, JsonSerializerOptions); } }
然后替换默认格式化器:
builder.Services.AddControllers(options => { var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, TypeInfoResolver = new JsonHierarchyTypeInfoResolver() }; options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>(); options.OutputFormatters.Add(new PolymorphicSystemTextJsonOutputFormatter(jsonOptions)); });
是否需要换回Json.Net?
无需急于换回Json.Net。以上方案均可解决WebAPI场景下的多态序列化问题,System.Text.Json在.NET 7+中已具备完善的多态支持,仅需针对WebAPI的序列化逻辑做针对性调整。如果项目多态需求极度复杂、调整成本过高,再考虑继续使用Json.Net。
内容的提问来源于stack exchange,提问作者Luis Abreu
相关产品推荐
相关产品推荐

