Removing assembly version and PublicKeyToken from serialized $type

Apr 1, 2010 at 3:46 AM

Hi,

I was wondering whether it is possible to remove the assembly version and public key token that appears when serializing using the

TypeNameHandling = TypeNameHandling.Objects

settings. I still want the full class name to be there, but just not the assembly version and public key token because I still want it to be deserialized in the future regardless of what assembly version it is.

 

Thanks

Leo

Coordinator
Apr 2, 2010 at 10:57 AM
Edited Apr 2, 2010 at 10:58 AM

I have added a TypeNameAssemblyFormat setting.

http://json.codeplex.com/SourceControl/list/changesets

Apr 26, 2010 at 2:19 PM
Edited Apr 26, 2010 at 2:31 PM

Would there be any reason why the TypeNameAssemblyFormat=FormatterAssemblyStyle.Simple value would not work in Silverlight for JsonSerializerSettings ? It seems to work fine with the regular Json.Net library, but with the Silverlight version, I get the following exception when I try to serialize an object using JsonConvert.SerializeObject:

 

System.MethodAccessException: Attempt to access the method failed: System.Reflection.Assembly.GetName()
   at Newtonsoft.Json.Utilities.ReflectionUtils.GetTypeName(Type t, FormatterAssemblyStyle assemblyFormat)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.WriteTypeProperty(JsonWriter writer, Type type)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonProperty member, JsonContract contract)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonSerializerSettings settings)

 

It works fine with the Silverlight version when you use TypeNameAssemblyFormat=FormatterAssemblyStyle.Full with the Silverlight version.

 

Apr 26, 2010 at 2:46 PM

Okay, the GetName() method has the SecurityCriticalAttribute attribute which causes the method to throw a MethodAccessException when code outside of the silverlight framework calls it (namely, application code that you write).  I am unsure as to why it is designed this way.  Here is the msdn reference:

 

http://msdn.microsoft.com/en-us/library/9w2wdeze%28VS.95%29.aspx

 

I downloaded the Json.Net source and made the following change to the ReflectionUtils.GetTypeName() method:

 

public static string GetTypeName(Type t, FormatterAssemblyStyle assemblyFormat)
    {
      switch (assemblyFormat)
      {
        case FormatterAssemblyStyle.Simple:
              string assemblyName = t.Assembly.FullName;
              return t.FullName + ", " + assemblyName.Substring(0, assemblyName.IndexOf(','));
          //return t.FullName + ", " + t.Assembly.GetName().Name;
        case FormatterAssemblyStyle.Full:
          return t.AssemblyQualifiedName;
        default:
          throw new ArgumentOutOfRangeException();
      }
    }

 

This workaround fixes the serialization problem, but there is now an exception that is thrown upon de-serialization. It's based on the fact that the assembly's culture is neutral and publickeytoken is null when you use the simple formatter style. If you already have an assembly loaded in your app domain that has a specific culture and/or publickeytoken, you will get the following exception that is thrown in the DefaultSerializationBinder class's BindToType() method:

 

The requested assembly version conflicts with what is already bound in the app domain or specified in the manifest. (Exception from HRESULT: 0x80131053)

 

Maybe the simple assembly name format shouldn't be supported in Silverlight?

 

 

Dec 29, 2010 at 12:58 PM

integragreg, I had the same problem, but I was able to fix that after reading the following post: http://inquisitorjax.blogspot.com/2009/10/gettype-from-referenced-assembly-in.html

the problem is solved, if you change Newtonsoft.Json.Serialization.DefaultSerializationBinder:

replace

assembly = Assembly.Load(assemblyName);

 

part with

if (assemblyName.IndexOf(',') != -1)
{
    // full qualified name
    assembly = Assembly.Load(assemblyName);
}
else
{
    var info = Application.GetResourceStream(new Uri(assemblyName + ".dll"UriKind.Relative));
    assembly = new AssemblyPart().Load(info.Stream);
}

 it works fine with both  FormatterAssemblyStyle.Full and FormatterAssemblyStyle.Simple, but I'm not aware of any performance implications.

 

for now, I just created my own SerializationBinder with the changed code of  DefaultSerializationBinder and provide it in JsonSerializerSettings. But it would be great if this could be included in next version of JSON.NET