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

.NET 6下SignalR切换至JsonProtocol抛出JsonException问题

问题解决:.NET 6 SignalR + System.Text.Json 序列化报错

问题根源

这个JSON解析错误的核心原因是:服务端与客户端切换到System.Text.Json后,未配置多态类型的序列化规则。之前使用Newtonsoft.Json时,TypeNameHandling.All会自动在JSON中嵌入类型标识信息,让两端能正确识别多态对象;而System.Text.Json默认不处理多态逻辑,导致传输的JSON结构缺失必要的类型元数据,客户端解析时出现格式异常。


解决方案

要实现Newtonsoft.Json TypeNameHandling.All的等效效果,需要在System.Text.Json中配置多态序列化规则,且服务端与客户端配置必须完全一致,同时适配你需要的源生成器+SerializerContext需求。

1. 配置服务端SignalR JsonProtocol

方式一:用特性标记多态类型(适配源生成器,推荐)

先在多态基类上添加JsonDerivedType特性,明确派生类与类型标识的映射:

// 基类标记多态规则
[JsonDerivedType(typeof(MessageA), typeDiscriminator: "MessageA")]
[JsonDerivedType(typeof(MessageB), typeDiscriminator: "MessageB")]
public class BaseMessage
{
    // 基类属性定义
}

// 派生类示例
public class MessageA : BaseMessage
{
    // 派生类属性
}

public class MessageB : BaseMessage
{
    // 派生类属性
}

然后在服务端配置中关联源生成的JsonSerializerContext(需提前定义包含所有多态类型的Context):

services.AddSignalR()
    .AddJsonProtocol(options =>
    {
        // 绑定源生成的序列化上下文
        options.PayloadSerializerOptions.TypeInfoResolver = AppJsonSerializerContext.Default;
    });

对应的源生成上下文定义:

[JsonSerializable(typeof(BaseMessage))]
[JsonSerializable(typeof(MessageA))]
[JsonSerializable(typeof(MessageB))]
public partial class AppJsonSerializerContext : JsonSerializerContext
{}
方式二:直接在序列化选项中配置多态(无需特性)

如果不想用特性标记,可直接在选项中声明多态规则:

services.AddSignalR()
    .AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.PolymorphismOptions = new JsonPolymorphismOptions
        {
            // 可选:指定类型标识字段名,与Newtonsoft的$type一致,方便过渡
            TypeDiscriminatorPropertyName = "$type",
            IgnoreUnrecognizedTypeDiscriminators = true,
            DerivedTypes =
            {
                new JsonDerivedType(typeof(MessageA), "MessageA"),
                new JsonDerivedType(typeof(MessageB), "MessageB")
                // 添加所有需要传输的派生类
            }
        };
        // 绑定源生成上下文(如果使用)
        options.PayloadSerializerOptions.TypeInfoResolver = AppJsonSerializerContext.Default;
    });

2. 客户端同步相同配置

客户端必须和服务端的序列化规则完全匹配,否则仍会解析失败:

conn = new HubConnectionBuilder()
    .WithUrl($"{_serverBaseAddress}mainHub", o =>
    {
        o.AccessTokenProvider = InitializeOrRefreshAccessTokenIfNeeded;
        o.Transports = HttpTransportType.WebSockets;
    })
    .ConfigureLogging(logging =>
    {
        logging.AddConsole();
    })
    .AddJsonProtocol(options =>
    {
        // 同步服务端的源生成上下文
        options.PayloadSerializerOptions.TypeInfoResolver = AppJsonSerializerContext.Default;
        // 同步多态规则
        options.PayloadSerializerOptions.PolymorphismOptions = new JsonPolymorphismOptions
        {
            TypeDiscriminatorPropertyName = "$type",
            IgnoreUnrecognizedTypeDiscriminators = true,
            DerivedTypes =
            {
                new JsonDerivedType(typeof(MessageA), "MessageA"),
                new JsonDerivedType(typeof(MessageB), "MessageB")
            }
        };
    })
    .Build();

关键注意事项

  • 类型标识字符串必须完全一致:如果之前用Newtonsoft生成的是完整程序集限定名(如YourNamespace.MessageA, YourAssembly),需在System.Text.Json中沿用相同的标识值,避免兼容问题。
  • 源生成上下文必须包含所有涉及的多态类型:否则会出现序列化/反序列化失败。

内容的提问来源于stack exchange,提问作者Sylvain Gantois

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:51:29