Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json.net deserialize json with circular reference in MVC4

I am trying with no luck to deserialize object graph with circular reference,

Json.net works well when serializing circular references : adding a $id to objects and replacing objects with $ref = *objectId, When i send the same data back to the MVC action, it won't deserialize correctly - replacing the $refs with empty objects.

I use json.net to both serialize and deserialize, deserializing is implemented in a custom IValueProvider - https://json.codeplex.com/discussions/347099

I noticed that when deserializing to an anonymous object

JsonConverter.Deserialize(json);

it will not deal with the circular references. but when deserializing using a generic type

JsonConverter.Deserialize<EntityType>(json) 

it will deserialize correctly.

But i can't find the type in the GetValueProvider(ControllerContext controllerContext)

any help will be appreciated

Edit- In my current fix i pass the whole json as a string and use

JsonConverter.Deserialize<EntityType>(json) 

with the right type in the controller's action, but that's definitely not the right way to work with json + mvc4... I need a better way to integrate it into mvc, started a bounty

Edit- More code The type :

[JsonObject(IsReference = true)]
public class DynamicEntity : EntityWithID<Guid>
{
    ....

    public virtual IList<DynamicEntity> ReferenceFields { get; set; }
}

The json to deserialize is the output of the Serialize method of Json.net.

{"$id":"1","ReferenceFields":[{"$ref":"1"}],"Id":"9f9de7f3-865e-4511-aeac-a2ff01193b06"}

The issue is the integration with MVC because the json goes back and forth between the server and client. I already have js methods to change it back and forth to the same exact format - tested as i use it like this for now :

public ActionResult EntitySaveOrUpdate(string entity)
    {
        var entityToSave = JsonConvert.DeserializeObject<DynamicEntity>(entity);
        ...
    }

And it works just fine, but i need a better integration with MVC and not deserialize in all of my actions...

like image 755
Royi Mindel Avatar asked Mar 30 '14 13:03

Royi Mindel


1 Answers

The challenge is dynamically typing at compile-time an un-typed languages (JSON).

Since JSON is actually Java-Script Object Notation, and JavaScript is weakly typed (or un-typed), the compile-time interpreter isn't sure if "1" refers to an int, double, or string type.

Notice, you don't get the same problem when you use a DynamicEntity, because the Run-Time is allowed to interpret in similar manner to JavaScript.

  • This post of how dynamics and static-anonymous-types treat deserialization is a little old, but still relevant. Their approach is to use JsonConvert.DeserializeAnonymousType() -- a dynamic method -- to return anonymous.

  • This post expands on Web Api's DataContractJsonSerializer, and how it limits your options with anonymous types. The answer suggested is to

"to replace the MediaTypeFormatter and plug in our own JSON serializer"

This amounts to a lot of work for your limited needs.

What you'll find is, short of using Linq projection, your DynamicEntity is probably as good approach as you will find.

like image 137
Dave Alperovich Avatar answered Oct 11 '22 00:10

Dave Alperovich