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

.NET 8.0 Blazor WASM迁移:序列化源码生成与多态问题咨询

Blazor WASM迁移至.NET 8.0的System.Text.Json源代码生成问题解答

背景

我们正将基于ASP.NET Core托管的现有Blazor WASM应用迁移至.NET 8.0,在裁剪(trimming)方面遇到诸多问题,其中之一是确保裁剪器不会移除Blazor WASM与Web API交互所用的类型。当前序列化/反序列化依赖基于反射的System.Text.Json且未启用裁剪,理论上迁移到源代码生成难度不大,但实际操作中遇到以下问题:


问题一:泛型类型的源代码生成序列化配置

项目中使用了如下泛型辅助类型:

public sealed record Descriptor<T>(T Value, string Description);

该类型用于API端点返回枚举值/字符串对,供Blazor WASM UI的下拉列表使用。尝试通过源代码生成序列化该类型时,需为派生自JsonSerializerContext的分部类添加JsonSerializableAttribute,但发现无法指定开放泛型类型,必须为每个闭合泛型(如Descriptor<Kind>、Descriptor<KindB>)添加属性;同时,若要序列化该类型的集合(如IEnumerable<Descriptor<Kind>>、List<Descriptor<Kind>>),也需单独添加对应的属性配置,否则无法正常序列化/反序列化。现咨询:

  1. 是否确实无法指定开放泛型类型?
  2. 是否必须通过JsonSerializableAttribute指定所有待序列化/反序列化的类型(包括闭合泛型集合)?

解答

  1. 是的,当前(.NET 8)System.Text.Json的源代码生成器不支持直接配置开放泛型类型。源代码生成器需要明确的闭合泛型类型来生成针对性的序列化逻辑,因为开放泛型无法确定具体的字段/属性结构,无法提前生成代码。
  2. 对于闭合泛型的集合类型,不需要单独添加JsonSerializableAttribute——只要你已经为Descriptor<Kind>添加了属性,源代码生成器会自动处理其集合类型(如List<Descriptor<Kind>>、IEnumerable<Descriptor<Kind>>)的序列化逻辑。但如果集合是嵌套的复杂泛型(比如List<Descriptor<Dictionary<string, int>>>),可能需要额外配置内层的闭合泛型类型。

问题二:自定义多态解析器与源代码生成的结合

我们没有Web API所用类型的源代码,API存在多态场景:控制器方法签名返回Base类型,但实际返回其派生类型。此前使用Json.NET序列化,迁移至System.Text.Json时,通过自定义DefaultJsonTypeInfoResolver实现了兼容Json.NET的多态鉴别器(属性名为$type,值为完整程序集限定名),代码如下:

public class JsonHierarchyTypeInfoResolver : DefaultJsonTypeInfoResolver
{
  public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
  {
    var jsonTypeInfo = base.GetTypeInfo(type, options);
    var jsonType = jsonTypeInfo.Type;

    if (jsonType == typeof(Equipamento))
    {
      jsonTypeInfo = GetTypeInfoForDevice(jsonTypeInfo);
    }
    // ... remaining code removed
  }

  private static JsonTypeInfo GetTypeInfoForDevice(JsonTypeInfo jsonTypeInfo)
  {
    jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
    {
      TypeDiscriminatorPropertyName = "$type",
      IgnoreUnrecognizedTypeDiscriminators = true,
      UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization
    };

    foreach (var jsonDerivedType in _derivedDevicesTypes)
    {
      jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(
        new JsonDerivedType(jsonDerivedType,
          jsonDerivedType.AssemblyQualifiedName!));
    }

    return jsonTypeInfo;
  }
}

现咨询:

  1. 能否将该自定义解析器与源代码生成的解析器结合使用?还是源代码生成仅支持通过JsonDerivedTypeAttribute实现多态?
  2. 若无法结合,是否必须重写带有多态属性的DTO程序集,才能复用基于多态/继承的API端点?

解答

  1. 可以结合使用,但需要调整实现方式:
    • 源代码生成器会生成一个继承自JsonSerializerContext的类,该类内部使用的是SourceGenerationJsonSerializerContext的解析逻辑。你可以创建一个复合解析器,将源代码生成的解析器和自定义的JsonHierarchyTypeInfoResolver组合起来。
    • 具体做法:在JsonSerializerOptions中设置TypeInfoResolver为JsonTypeInfoResolver.Combine,传入源代码生成的上下文实例(如MyJsonSerializerContext.Default)和你的自定义解析器。这样系统会优先使用源代码生成的类型信息,对于未覆盖的类型(或需要多态处理的类型),再由自定义解析器补充处理。
    • 注意:如果源代码生成的上下文已经包含了Equipamento类型的配置,需要确保自定义解析器的逻辑能正确覆盖或补充其多态配置。
  2. 不需要重写DTO程序集。除了使用JsonDerivedTypeAttribute,你还可以:
    • 继续使用自定义的JsonHierarchyTypeInfoResolver,同时为需要裁剪保护的类型添加JsonSerializableAttribute(确保源代码生成器包含这些类型,避免被裁剪)。
    • 或者通过JsonSerializerOptions的PolymorphismOptions手动配置多态规则,不需要修改DTO的源代码。如果结合源代码生成,只需要在上下文中标记基类为可序列化,然后在选项中补充多态配置即可。

内容的提问来源于stack exchange,提问作者Luis Abreu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:34:55