Json.Net Deserialization with Castle.DynamicProxy2

May 17, 2010 at 4:48 PM
Edited May 17, 2010 at 4:51 PM
Hi,

I'm trying to deserialize some Json to dynamicaly created classes via a dynamic proxy with JsonConvert.DeserializeObject, but it doesn't like the dynamic classes ;-)
I found the problem in DefaultContractResolver.CreateContract.
The proxy object is an ISerializable so it returns CreateISerializableContract(objectType) which is not handled in JsonSerializerInternalReader.Populate and I get this Exception:
JsonSerializationException("Cannot populate JSON object onto type '{0}'.".FormatWith(CultureInfo.InvariantCulture, objectType));
here is my code (shortened):
public interface IPerson
{
  string Name { get; set; }
}

public class IPersonConverter : CustomCreationConverter<IPerson>
{
  public override IPerson Create(Type objectType)
  {
    var generator = new ProxyGenerator();
    var personIterceptor = new PersonInterceptor();
    var proxy = generator.CreateInterfaceProxyWithoutTarget(typeof(IPerson), personIterceptor);
    return (IPerson)proxy;
  }
}

...
    [Test]
    public void deserialize_dp_object_from_json_does_not_work()
    {
      var p = new Person();
      p.Name = "Foo Bar";
      
      var sw = new StringWriter();
      var serializer = new JsonSerializer();
      serializer.NullValueHandling = NullValueHandling.Ignore;
      
      using (var writer = new JsonTextWriter(sw))
      {
        serializer.Serialize(sw, p);
      }
      var ip = (IPerson)JsonConvert.DeserializeObject(sw.ToString(), typeof(IPerson), new IPersonConverter()); // throws Exception
      Assert.AreEqual(ip.Name, "Foo Bar");
    }
...

My workaround is to inherit from DefaultContractResolver like this (Castle.DynamicProxy proxies are IProxyTargetAccessor):
  public class DPContractResolver : DefaultContractResolver
  {
    protected override JsonContract CreateContract(Type objectType)
    {
      if (typeof(IProxyTargetAccessor).IsAssignableFrom(objectType))
      {
        return CreateObjectContract(objectType);
      }
      return base.CreateContract(objectType);
    }
  }
And then with this code the test will secceed:
...
    [Test]
    public void deserialize_dp_object_from_json()
    {
      var p = new Person();
      p.Name = "Foo Bar";
      var sw = new StringWriter();
      var serializer = new JsonSerializer();
      serializer.NullValueHandling = NullValueHandling.Ignore;
      using (var writer = new JsonTextWriter(sw))
      {
        serializer.Serialize(sw, p);
      }
      var settings = new JsonSerializerSettings();
      settings.Converters.Add(new IPersonConverter());
      settings.ContractResolver = new DPContractResolver();
      var ip = (IPerson)JsonConvert.DeserializeObject(sw.ToString(), typeof(IPerson), settings); // no exception - using custom ContractResolver
      Assert.AreEqual(ip.Name, "Foo Bar");
    }
...
Can someone please tell me why Populate does not handle JsonISerializableContract or where is the problem?
I don't want to step to deep in Json.NET code .. so much code .. so less time ;-)
Thx!