Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid having duplicate objects in WCF over protobuf

I've a small units tests to test circular dependencies.

My object is the following:

[ProtoContract]
public class Node
{
    [ProtoMember(1)]
    public String Name { get; set; }

    [ProtoMember(2,AsReference = true)]
    public List<Node> Childs { get; set; }

    public Node()
    {
        Childs = new List<Node>();
    }
}

And the following service:

[ServiceContract]
public interface INodeService : IService
{
    [OperationContract]
    Task<Node> GetCyclicNodes();
}

public class NodeService : Service, INodeService
{
    public async Task<int> Add(int a, int b)
    {
        return a + b;
    }

    public async Task<Node> GetCyclicNodes()
    {
        Node nodeA = new Node() {Name = "Node A"};
        Node nodeB = new Node() {Name = "Node B"};
        Node nodeC = new Node() {Name = "Node C"};
        nodeA.Childs.Add(nodeB);
        nodeB.Childs.Add(nodeC);
        nodeC.Childs.Add(nodeA);
        return nodeA;
    }
}

On client side I count the number of objects:

    private int CountNodes(Node node, List<Node> countedNodes = null)
    {
        if (countedNodes == null)
        {
            countedNodes = new List<Node>();
        }
        if (countedNodes.Contains(node))
        {
            return 0;
        }
        else
        {
            countedNodes.Add(node);
            int count = 1;
            foreach (Node nodeChild in node.Childs)
            {
                count += CountNodes(nodeChild, countedNodes);
            }
            return count;
        }
    }

When I call it, I would expect to receive the whole hierarchy, with 3 unique objects instances(one for "Node A", "Node B", "Node C").

But it seems that I've 4 differents objects, two times the object A.

Since my class is not AsReferenceDefault, I'm a little bit afraid that it doesn't see it is the same object than the one it gets.

In my case, I've a very big business model(~500 different models), which all herits from the same root class. Every class can be technically(in a model point of view) referenced by another one, it's always very clear that every class a ONE and ONLY ONE owner, and the other ones are only referring to it. Is this something I can do with protobuf?

Because even I don't know what is happening behind the scene when using references, I'm a little bit afraid it implies an unique ID is put on EVERY field, even if they are not referenced

EDIT

In fact, even while setting the AsReferenceDefault = true on the ProtoContract, I still get 4 objects instead of 3, now I'm a little bit lost.

EDIT 2

I did make another test, I tried to have a Container class(my differents operations return now some Task<Container<Node>>. This Container contains only one property which is marked as AsReference = true. Now it works, I've only 3 instances.

But seems to implies that I didn't understood properly the AsReference mechanism. I was thinking it was possible to have one "owner" of the object, which is NOT marked with the AsReference=true, and all the other ones that also reference this object would be AsReference =true. But if I understand properly, this will result in having 2 different instances?

If yes, I don't understand the advantage of setting AsReference = true over the AsReferenceDefault?

Did I understood properly?

like image 332
J4N Avatar asked Jul 17 '17 11:07

J4N


1 Answers

To me it looks as if the question is similar to this question where we realized a problem with the root level entity.

What we had as well is that for child object the reference where correct but the if the root item was referenced again a copy was there after deserialization.

Our work-around that we used for some time (and then we switched to pure JSON) was to add an extra root node. With this extra root node references where deseriliazed correctly. So this might be a work-around you could try as well.

like image 138
Sjoerd222888 Avatar answered Jan 03 '23 00:01

Sjoerd222888