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

求助:Newtonsoft中不同运行时加载程序集的类JSON类型不兼容

解决多版本程序集并行加载时Newtonsoft.Json反序列化类型冲突问题

针对你遇到的问题——同一服务中加载同名不同版本(甚至同版本但不同加载上下文)的程序集后,Newtonsoft.Json反序列化时因$type字段指向的程序集版本与当前目标类型不匹配导致的冲突,这里提供几个可行的解决思路:

1. 自定义序列化绑定器,忽略程序集版本或指定目标程序集

核心思路是替换Newtonsoft默认的类型解析逻辑,让它在解析$type字段时,忽略版本信息,或者直接从当前要使用的插件程序集中查找类型,而非依赖全局的Type.GetType。

示例代码:

public class PluginTypeBinder : ISerializationBinder
{
    private readonly Assembly _targetAssembly;

    public PluginTypeBinder(Assembly targetAssembly)
    {
        _targetAssembly = targetAssembly;
    }

    public Type BindToType(string assemblyName, string typeName)
    {
        // 直接从目标插件程序集中查找类型,跳过全局类型解析
        return _targetAssembly.GetType(typeName);

        // 若需保留类型名匹配但忽略版本,可拆分程序集信息后处理
        // var assemblyInfo = new AssemblyName(assemblyName);
        // assemblyInfo.Version = null;
        // return Type.GetType($"{typeName}, {assemblyInfo}", throwOnError: false);
    }

    public void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        // 序列化时输出不带版本的程序集名称,避免后续反序列化版本冲突
        typeName = serializedType.FullName;
        assemblyName = serializedType.Assembly.GetName().Name;
    }
}

使用方式:
加载插件程序集后,为该插件配置专属的JsonSerializerSettings:

var pluginAssembly = PluginLoader.CreateFromAssemblyFile("path/to/plugin.dll").LoadDefaultAssembly();
var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    SerializationBinder = new PluginTypeBinder(pluginAssembly)
};

// 反序列化时使用该专属配置
var obj = JsonConvert.DeserializeObject<YourBaseType>(json, settings);

2. 为每个插件实例独立维护JsonSerializer配置

每个加载的程序集(插件)对应一套独立的JsonSerializerSettings,确保反序列化时始终从当前插件的程序集中解析类型,彻底避免全局类型混淆。该方案需配合上述自定义绑定器使用,是最直接的隔离方案。

3. 禁用TypeNameHandling,改用固定类型反序列化

如果JSON结构固定、无需多态类型解析,可以直接禁用TypeNameHandling,指定明确的目标类型进行反序列化,完全绕过$type字段的解析逻辑:

// 直接指定目标类型,不依赖$type字段
var obj = JsonConvert.DeserializeObject<DerivedClass>(json);

这种方式最简单,但仅适用于不需要多态序列化的场景。

4. 强化程序集加载的上下文隔离

使用McMaster.DotNetCorePlugins的PluginLoadContext为每个版本的程序集创建独立的加载上下文,避免不同版本的程序集类型被全局加载上下文混淆:

// 为v1版本插件创建独立加载上下文
var loadContext1 = new PluginLoadContext("plugin-v1", isCollectible: true);
var assembly1 = loadContext1.LoadFromAssemblyFile("path/to/plugin-v1.dll");

// 为v2版本插件创建独立加载上下文
var loadContext2 = new PluginLoadContext("plugin-v2", isCollectible: true);
var assembly2 = loadContext2.LoadFromAssemblyFile("path/to/plugin-v2.dll");

配合自定义的PluginTypeBinder,确保每个上下文的类型解析只在自己的程序集中进行,彻底消除类型冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 13:33:36