.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
相关产品推荐
相关产品推荐

