Newtonsoft.Json 12.0.0.0序列化Hashtable&抛异常,求助解决
解决Newtonsoft.Json 12.0.0.0中Hashtable引用参数的序列化异常问题
这个问题的核心是Newtonsoft.Json 12.0版本对字典类型的序列化/反序列化逻辑做了严格升级,同时你的API设计本身存在不符合Web API规范的地方,两者叠加导致了这个500错误。下面是具体的分析和解决方案:
问题原因
- Json.NET 12的类型检查变更:在11.0及以前的版本中,Json.NET对
Hashtable的引用传递(Hashtable&)做了宽松处理,会将其识别为字典类型进行序列化;但12.0版本开始严格校验类型,Hashtable&(引用传递的Hashtable)不再被判定为字典类型,直接抛出异常。 - HttpGet + FromBody的不规范设计:REST规范中,GET请求通常不携带请求体,虽然部分工具(比如Swagger UI)支持发起带Body的GET请求,但这不符合标准,且Web API对GET请求的Body参数绑定本身就存在兼容性问题,这也加剧了异常出现的概率。
解决方案
方案1:重构API参数设计(推荐,符合最佳实践)
这是最彻底的解决办法,同时能让你的API更符合Web开发规范:
- 将
[HttpGet]改为[HttpPost]:用POST请求来传递请求体,符合REST规范,也能避免GET请求Body绑定的兼容性问题。 - 移除
ref关键字:Web API的参数绑定是基于请求内容反序列化为新对象,ref在这里没有实际意义,反而会干扰Json.NET的序列化逻辑。 - 替换
Hashtable为泛型Dictionary<string, object>:泛型类型类型安全,Json.NET对其支持更完善,后续维护也更方便。如果业务逻辑必须使用Hashtable,可以在方法内部将Dictionary转换为Hashtable。
修改后的代码示例:
[HttpPost] public SortedList<int, XElement> getVariableStates(string sInstanceID, [FromBody] Dictionary<string, object> oVarsDic) { // 若需要Hashtable,可在此处转换 var hashtable = new Hashtable(oVarsDic); // 你的业务逻辑代码 // ... }
方案2:自定义JsonConverter兼容Hashtable引用参数(不推荐,仅用于无法重构的场景)
如果因为历史原因无法修改API结构,可以通过自定义转换器让Json.NET识别Hashtable&类型:
- 创建自定义转换器:
public class HashtableRefConverter : JsonConverter { public override bool CanConvert(Type objectType) { // 匹配Hashtable的引用传递类型(Hashtable&) return objectType == typeof(Hashtable).MakeByRefType(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 将JSON反序列化为Hashtable return serializer.Deserialize<Hashtable>(reader); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // 序列化Hashtable对象 serializer.Serialize(writer, value); } }
- 注册转换器:
在Startup.cs中添加转换器到Json.NET配置:
services.AddMvc().AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new HashtableRefConverter()); });
或者直接在参数上标记转换器:
public SortedList<int, XElement> getVariableStates(string sInstanceID, [FromBody][JsonConverter(typeof(HashtableRefConverter))] ref Hashtable oVarsDic) { // 业务逻辑 }
方案3:临时回退到Newtonsoft.Json 11.0.0.0
如果以上方案都无法快速实施,可以暂时回退到11.0.0.0版本来恢复正常运行,但这只是临时解决办法,长期来看会错过Json.NET的安全更新和功能优化,不推荐作为最终方案。
最佳实践建议
- 避免在Web API中使用
ref/out参数:Web API的参数模型是基于请求内容构建对象,引用传递在这里没有实际作用,反而会引入不必要的兼容性问题。 - 优先使用泛型集合:泛型
Dictionary<TKey, TValue>比非泛型Hashtable类型更安全,序列化/反序列化的兼容性更好,代码可读性也更高。 - 遵循REST规范:GET请求用于查询资源,不携带请求体;POST/PUT请求用于提交/更新数据,通过请求体传递参数。
内容的提问来源于stack exchange,提问作者Ravi K




