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>
我使用这篇文章找到了解决方案的一部分:
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);
}
}