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

Newtonsoft.Json反序列化System.Type抛出JsonSerializationException求助

问题分析与解决方案

核心问题

异常本质是反序列化时无法根据JSON中带版本号的程序集限定名找到对应System.Type,仅在新环境出现的原因是:老环境存在程序集绑定重定向、本地旧版本DLL缓存或GAC安装记录,而新环境缺少这些配置/文件,导致Type.GetType()无法定位到目标类型。

解决方案

1. 自定义Type转换器,忽略版本号加载类型

在反序列化时手动剥离版本信息,从当前加载的程序集中匹配类型:

// 自定义转换器:忽略版本号解析Type
public class TypeIgnoreVersionConverter : JsonConverter<Type>
{
    public override Type ReadJson(JsonReader reader, Type objectType, Type existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var fullTypeName = reader.Value as string;
        if (string.IsNullOrEmpty(fullTypeName))
            return null;
        
        // 拆分类型名与程序集信息,剔除版本、公钥等冗余部分
        var typeAssemblyParts = fullTypeName.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
        if (typeAssemblyParts.Length < 2)
            return Type.GetType(fullTypeName);
        
        var typeName = typeAssemblyParts[0];
        var assemblyName = typeAssemblyParts[1].Split(new[] { ", Version=" }, StringSplitOptions.RemoveEmptyEntries)[0];
        
        // 从当前AppDomain加载的程序集中查找目标类型
        var targetAssembly = AppDomain.CurrentDomain.GetAssemblies()
            .FirstOrDefault(a => a.GetName().Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase));
        
        return targetAssembly?.GetType(typeName, true);
    }

    public override void WriteJson(JsonWriter writer, Type value, JsonSerializer serializer)
    {
        writer.WriteValue(value.AssemblyQualifiedName);
    }
}

修改CloneJson方法的序列化配置,添加该转换器:

public static T CloneJson<T>(this T source)
{
 if ((object)source == null)
     return default(T);
 var settings = new Newtonsoft.Json.JsonSerializerSettings()
 {
     NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
     ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace,
     TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto,
     Converters = new List<JsonConverter> { new TypeIgnoreVersionConverter() } // 添加自定义转换器
 };
 var serializedObj = Newtonsoft.Json.JsonConvert.SerializeObject((object)source, settings);
 var deserializedOjb = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(serializedObj, settings);
 return deserializedOjb;
}

2. 添加程序集绑定重定向

在项目的App.config中配置绑定重定向,强制所有版本的目标程序集指向当前环境的版本:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="CompanyName.ApplicationName.Common.Objects" publicKeyToken="null" culture="neutral" />
        <!-- 替换newVersion为你当前环境的程序集版本号 -->
        <bindingRedirect oldVersion="0.0.0.0-99.99.99.99" newVersion="1.0.8977.16740" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

3. 调整序列化配置,避免存储完整版本号

如果不需要跨程序集的类型识别,可以修改TypeNameHandling并自定义序列化逻辑,只存储类型全名和程序集名称:

public class TypeSimpleNameConverter : JsonConverter<Type>
{
    public override Type ReadJson(JsonReader reader, Type objectType, Type existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var typeInfo = reader.Value as string;
        return Type.GetType(typeInfo, true);
    }

    public override void WriteJson(JsonWriter writer, Type value, JsonSerializer serializer)
    {
        // 只输出类型全名+程序集名称,不带版本、公钥信息
        writer.WriteValue($"{value.FullName}, {value.Assembly.GetName().Name}");
    }
}

然后在CloneJson的settings中替换TypeNameHandling为None并添加该转换器。

排查验证步骤

  • 检查新环境输出目录中CompanyName.ApplicationName.Common.Objects.dll的版本,对比JSON中的版本号是否一致
  • 复制团队成员的App.config配置到本地,确认是否存在绑定重定向
  • 用ILSpy查看编译输出的程序集版本,确认项目引用的版本与实际输出一致
  • 检查本地GAC是否安装了旧版本的目标程序集,如有则卸载

内容的提问来源于stack exchange,提问作者Jacob Thomas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 07:17:10