SignalR发送List<object>时调用ToString而非JSON序列化问题排查
问题根源
你遇到的核心问题是:Convert.ChangeType返回的是object类型,因此animalsAsType的实际类型为List<object>。SignalR的默认序列化器在处理object类型的集合元素时,无法识别其具体子类(Dog/Cat)的类型信息,会直接调用ToString()方法输出,而非序列化对象的属性。
解决方案
方案一:通过泛型+反射保留强类型信息
既然SendChanges的签名无法修改,我们可以用私有泛型方法完成类型转换,再通过反射调用该泛型方法,得到强类型的列表(List<T>而非List<object>),让SignalR能正确序列化属性。
代码示例:
public abstract class Animal {} public class Dog : Animal { public bool GoodBoy { get; set; } public override string ToString() { return "hello from dog"; } } public class Cat : Animal { public bool Hungry { get; set; } } public class MyHub : Hub { // 私有泛型转换方法:类型不匹配时会抛出InvalidCastException private List<T> CastAnimals<T>(List<Animal> animals) where T : Animal { return animals.Cast<T>().ToList(); } public void SendChanges(Type type, List<Animal> animals) { // 反射调用泛型转换方法 var castMethod = typeof(MyHub).GetMethod(nameof(CastAnimals), BindingFlags.NonPublic | BindingFlags.Instance)!; var genericCastMethod = castMethod.MakeGenericMethod(type); var typedAnimals = genericCastMethod.Invoke(this, new object[] { animals })!; // 发送强类型列表,SignalR会正确序列化属性 Clients.Others.SendAsync($"On{type.Name}Changed", typedAnimals); } }
方案二:配置SignalR序列化器开启多态支持
如果不想用反射,可以直接配置SignalR的JSON序列化选项,添加Animal的子类类型信息,让序列化器能识别多态类型,这样直接发送List<Animal>也能得到正确结果。
在Program.cs(或Startup.cs)中配置:
builder.Services.AddSignalR() .AddJsonProtocol(options => { options.PayloadSerializerOptions.TypeInfoResolverChain.Insert(0, new DefaultJsonTypeInfoResolver { Modifiers = { typeInfo => { if (typeInfo.Type == typeof(Animal)) { typeInfo.PolymorphismOptions = new JsonPolymorphismOptions { TypeDiscriminatorPropertyName = "$type", // 可选:指定类型判别字段名 IgnoreUnrecognizedTypeDiscriminators = true, DerivedTypes = { new JsonDerivedType(typeof(Dog), nameof(Dog)), new JsonDerivedType(typeof(Cat), nameof(Cat)) } }; } } } }); });
配置完成后,直接发送原列表即可:
public void SendChanges(Type type, List<Animal> animals) { Clients.Others.SendAsync($"On{type.Name}Changed", animals); }
补充说明
- 你之前的
Convert.ChangeType操作本身没有语法错误,但由于返回类型是object,导致SignalR无法识别具体子类,才会触发ToString()。 - 用
Cast<T>替代Convert.ChangeType的好处是:类型不匹配时会直接抛出InvalidCastException,符合你要求的“实例类型不匹配则抛出异常”的需求。
内容的提问来源于stack exchange,提问作者Sillydan
相关产品推荐
相关产品推荐

