문제

I'm trying to serialize (and later on deserialize) a Dictionary<string, ISet<string>>. Unfortunately, Json.NET (v6.0.3 via NuGet) fails to do this. What I do is

var value = new Dictionary<string, ISet<string>>
    {
        {"foo", new HashSet<string>{"bar"}}
    };
var settings = new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.Objects,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
    };
var json = JsonConvert.SerializeObject(value, settings);

The variable json then holds the string

{"$type":"System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.ISet`1[[System.String, mscorlib]], System]], mscorlib","foo":["bar"]}

Now I want to deserialize the string with

JsonConvert.DeserializeObject<IDictionary<string, ISet<string>>>(json, settings);

which fails in resolving the Dictionary type, because it cannot find the System assembly that ISet belongs to. When I instead do the following

JsonConvert.DeserializeObject<IDictionary<string, ISet<string>>>(json);

everything works just fine. So it appears that the TypeNameHandling setting (changing/omitting the format does not change anything) actually breaks deserialization.

I found that, if I don't set the TypeNameHandling settings, the serialized $type properties are simply ignored. I.e., when deserializing, the type information is taken solely from the target type where they are resolved. This works.

When setting the TypeNameHandling, type resolution happens via reflection within the Json.NET assembly, which does not have a dependency on the System assembly and therefore fails to resolve the ISet interface. I can fix this by registering on AppDomain.CurrentDomain.AssemblyResolve and resolving the assembly like so

if (args.Name == "System")
{
     return typeof (ISet<>).Assembly;
}

but this seems very fragile to me, as it solves the problem for only this one specific assembly and I have to add another case for every assembly I need somewhere.

Does anyone have experience on how to solve this? Any help is greatly appreciated!

도움이 되었습니까?

해결책

Similar problem was addressed in the following thread: How can I deserialize with TypeNameHandling.Objects in Json.NET Silverlight?

The problem seems to be that Json is failing to load the assembly with partial name. You could overcome this issue by using TypeNameAssemblyFormat = FormatterAssemblyStyle.Full.

다른 팁

If you check the source code for NewtonSoft.Json in DefaultSerializationBinder.GetTypeNameFromTypeNameKey approx. row 83.. It tries to get the type

System.Collections.Generic.Dictionary2[[System.String, mscorlib],[System.Collections.Generic.ISet1[[System.String, mscorlib]], System]]

from assembly

mscorlib.dll

Type type = assembly.GetType(typeName);

Which returns null. This is with FormatterAssemblyStyle.Simple.

If you use FormatterAssemblyStyle.Full then the same type will be:

System.Collections.Generic.Dictionary2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.ISet1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]

And then:

Type type = assembly.GetType(typeName);

Will work and hence the deserialization works as well.

I cant say why this is the case though.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top