Newtonsoft.Json FormatterAssemblyStyle=Simple在反序列化时仍然需要程序集名称

本文关键字:程序集 FormatterAssemblyStyle Json Simple 反序列化 Newtonsoft | 更新日期: 2023-09-27 18:19:45

我需要能够反序列化在运行时加载的不同程序集中的对象。装载组件代码:

foreach (string asmPath in Directory.GetFiles(PLUGIN_DIRECTORY, "*.dll"))
{
    var AsmName = AssemblyName.GetAssemblyName(asmPath);
    var Asm = Assembly.Load(AsmName);
    _LoadedAssemblies.Add(Asm);
}

程序集加载得很好,当反序列化具有整个程序集名称的对象时

"$type": "Plugin.MyRules.Rule1, SmartPlugin, Version=1.0.3.0, Culture=neutral, PublicKeyToken=null"

一切都很顺利。我现在需要做的是能够在运行时加载程序集的任何版本,而无需提供版本信息。我认为使用FormatterAssemblyStyle.Simple设置可以通过使用的简单类型来排除名称中的版本

"$type": "Plugin.MyRules.Rule1, SmartPlugin"

但事实并非如此。它显然永远找不到我加载的程序集名称。我很感激在这方面的任何帮助。

这是我正在使用的反序列化程序代码:

public static T DeserializeJsonObject<T>(string p_JSONPath)
{
    T returnVal = default(T);
    using (StreamReader reader = new StreamReader(new FileStream(p_JSONPath, FileMode.Open)))
    {
        returnVal = JsonConvert.DeserializeObject<T>(reader.ReadToEnd(), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple });
    }
    return returnVal;
}

我还应该提到,这是Newtonsoft的例外:

Could not load assembly 'SmartPlugin'.

这是堆栈跟踪:

at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at JSONSerializer.DeserializeJsonObject[T](String p_JSONPath) in c:'EXAMPLE.cs:line 15

在运行时加载程序集的这种情况下,通过添加到app.config来重定向程序集绑定似乎也不起作用。当它们被反射时,仍然作为dll本身的程序集版本加载。

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="SmartPlugin" publicKeyToken="null" culture="en-us" />
      <!-- Assembly versions can be redirected in app, publisher policy, or machine configuration files. -->
      <bindingRedirect oldVersion="0.0.0.0-999.999.999.999" newVersion="1.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Newtonsoft.Json FormatterAssemblyStyle=Simple在反序列化时仍然需要程序集名称

我使用这篇文章找到了解决方案的一部分:

https://stackoverflow.com/a/9921190/2996906

我没有像那个用户那样使用迁移,只是浏览了加载的程序集的列表,并比较了程序集名称而不是全名。然后,如果匹配,则返回用于构建类型的集合的全名。我还将CustomNamespaceSerializationBinder添加到JsonSerializerSettings中的Binder属性中。

public class CustomNamespaceSerializationBinder : DefaultSerializationBinder
{
    public override Type BindToType(string assemblyName, string typeName)
    {
        foreach (Assembly asm in PluginLoader.GetPluginAssemblies())
        {
            if (asm.FullName.Contains(assemblyName))
            {
                assemblyName = asm.FullName;
                break;
            }
        }
        return base.BindToType(assemblyName, typeName);
    }
}