3

I have two objects which reference each other.

    [JsonObject(IsReference = true)]
    [DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
    [ProtoContract]
    public class ProtoBufObject : ITrackable
    {
        [DataMember(Order = 3)]
        public Guid Oid { get; set; }
        [DataMember(Order = 4)]
        [ProtoMember(4, AsReference = true)]
        public ChildProtoBufObject child { get; set; }
        [DataMember(Order = 1)]
        public TrackingState TrackingState { get; set; }
        [DataMember(Order = 2)]
        public ICollection<string> ModifiedProperties { get; set; }
    }

    [JsonObject(IsReference = true)]
    [DataContract(IsReference = true, Namespace = "http://schemas.datacontract.org/2004/07/TrackableEntities.Models")]
    [ProtoContract]
    public class ChildProtoBufObject : ITrackable
    {

        [DataMember(Order = 3)]
        public Guid Oid { get; set; }

        [DataMember(Order = 4)]
        [ProtoMember(4, AsReference = true)]
        public ProtoBufObject parent { get; set; }

        [DataMember(Order = 1)]
        public TrackingState TrackingState { get; set; }
        [DataMember(Order = 2)]
        public ICollection<string> ModifiedProperties { get; set; }
    }

On the client I instantiate this objects and make the "associations".

 ProtoBufObject parent = new ProtoBufObject()
         {
             Oid = Guid.NewGuid()
         };
         ChildProtoBufObject child = new ChildProtoBufObject()
         {
             Oid = Guid.NewGuid()
         };
         parent.child = child;
         child.parent = parent;

The objects will be serialized like this:

    ProtoBufFormatter formatter = new ProtoBufFormatter();
    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri);
    requestMessage.Content = new ObjectContent<SearchParameters>(searchParameters, formatter);

And than they will be sent via http to a Webapi, where it will be deserialized with the help of WebApiContrib.Formatting.ProtoBuf.

In the Webapi controller i receive the objects with the correct relations BUT the integrity of the relations gone wrong. I dump the objects with Json to a file with this piece of code:

 string json = JsonConvert.SerializeObject(samples);
            //write string to file
            string oid = samples.First().Oid.ToString();
            System.IO.File.WriteAllText(@"D:\JsonTest\dummypath" + oid + ".txt", json);

And here is what this text file looks like

[{
    "$id": "1",
    "TrackingState": 0,
    "ModifiedProperties": null,
    "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
    "child": {
        "$id": "2",
        "TrackingState": 0,
        "ModifiedProperties": null,
        "Oid": "81026a01-7de2-4045-ac0a-314b3fd7360c",
        "parent": {
            "$id": "3",
            "TrackingState": 0,
            "ModifiedProperties": null,
            "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
            "child": {
                "$ref": "2"
            }
        }
    }
}]

the child has a "new" parent with id=3 instead of a ref=1. The id=3 parent has the correct reference to the child.

So it seams that the top level object will not set up correctly. This is a huge problem with Entity Framework (that's why I came up with this issue) because it uses the reference of the type, not just to properties (which are correct).

I also tried it with ProtoContract(DefaultRefencetype=true) but that made it even worser. Then I received on the parent with id=3 a new child with id=4.

My question is: How I can make the integrity of the objects to work?

What I want is:

[{
    "$id": "1",
    "TrackingState": 0,
    "ModifiedProperties": null,
    "Oid": "8c00ea73-ac84-4130-b1a8-61e1df89f9bf",
    "child": {
        "$id": "2",
        "TrackingState": 0,
        "ModifiedProperties": null,
        "Oid": "81026a01-7de2-4045-ac0a-314b3fd7360c",
        "parent": {
            "$ref": "1"
            }
        }
    }
}]

Edit: The Entity Framework line

dbContext.Set<ProtoBufObject>.AddRange(myObjects);

throws an InvalidOperationException because the integrity of the models (parent, child.parent) differ.

Additional information: Conflicting changes to the role 'foo_bar_Target' of the relationship 'Entities.Context.foo_bar' have been detected.

If I use the Newtonsoft.Json serializer on the client side and send it through the WebApi (I use the same objects with the same relations as with my Protobuf test) the Entity Framework can handle the objects. So there must be some differences between the deserialised objects from Json and Protobuf. That's why I serialized the objects again to see the differences.

I also put in my Put method a reference check:

if (protoBufObject != protoBufObject.child.parent)
{
    throw new Exception("Instance integrity differs!");
}

as expected from the json file this exeption is thrown, so the references are really corrupted.

In the Startup of the WebApi I use following code:

        config.Formatters.Add(new ProtoBufFormatter());

Lies there the problem? Do I need to add some more information to the Formatters?

Oliver Müller
  • 545
  • 1
  • 5
  • 17
  • 1
    What, other than JSON, makes you think the relationships are broken? For example, this works fine: http://pastie.org/9280110 - can you show something that demonstrates the code not behaving as expected? – Marc Gravell Jun 11 '14 at 13:17
  • I have edited my post with the Entity Framework line which make me think that the relationship is broken. – Oliver Müller Jun 12 '14 at 09:31
  • The root object is referenced by a child object and for some reason protobuf-net creates a copy in serialization instead of a proper reference. A workaround would be to put everything into another root object. – Sjoerd222888 Jun 22 '14 at 17:59
  • Do you have any solution or is this a remaining issue? – Oliver Müller Oct 16 '14 at 09:17

0 Answers0