You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Newtonsoft.Json 12.0.0.0序列化Hashtable&抛异常,求助解决

解决Newtonsoft.Json 12.0.0.0中Hashtable引用参数的序列化异常问题

这个问题的核心是Newtonsoft.Json 12.0版本对字典类型的序列化/反序列化逻辑做了严格升级,同时你的API设计本身存在不符合Web API规范的地方,两者叠加导致了这个500错误。下面是具体的分析和解决方案:

问题原因

  1. Json.NET 12的类型检查变更:在11.0及以前的版本中,Json.NET对Hashtable的引用传递(Hashtable&)做了宽松处理,会将其识别为字典类型进行序列化;但12.0版本开始严格校验类型,Hashtable&(引用传递的Hashtable)不再被判定为字典类型,直接抛出异常。
  2. 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&类型:

  1. 创建自定义转换器:
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);
    }
}
  1. 注册转换器:
    在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

火山引擎 最新活动