2

I need to be able to deserialize objects that are part of a different assembly that is loaded at runtime. Loading assemblies code:

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

The assemblies are loaded just fine, and when deserializing the objects with the entire assembly name of

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

everything works fine and dandy. What I now need to happen is to be able to load any version of the assembly at runtime without supplying the version information. I figured that using the FormatterAssemblyStyle.Simple setting would allow me to exclude the version in the name by using a simple type of

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

but that is not the case. It apparently cannot ever find my loaded assembly name. I would appreicate any help on this.

This is the deserializer code I am using:

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;
}

I should also mention that this is the Newtonsoft exception:

Could not load assembly 'SmartPlugin'.

This is the stack trace:

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

Re-direction of the assembly bindings by adding to the app.config doesn't seem to work either in this scenario where assemblies are loaded at run-time. The are still loaded as the assembly version of the dll itself when they are reflected.

<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>
sidE
  • 21
  • 5

1 Answers1

0

I found part of the solution using this post:

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

Instead of using the migrations as that user did, I just ran through the list of my loaded assemblies, and compared the assembly name instead of the full name. Then if something matched, return the full name of the assemble to build the type. I also added the CustomNamespaceSerializationBinder to the Binder property in the JsonSerializerSettings.

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);
    }
}
Community
  • 1
  • 1
sidE
  • 21
  • 5