You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 20:01:43