如何避免在 protobuf 上的 WCF 中有重复的对象

Posted

技术标签:

【中文标题】如何避免在 protobuf 上的 WCF 中有重复的对象【英文标题】:How to avoid having duplicate objects in WCF over protobuf 【发布时间】:2017-07-17 11:54:28 【问题描述】:

我有一个小单元测试来测试循环依赖。

我的对象如下:

[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>();
    

还有以下服务:

[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;
    

在客户端我计算对象的数量:

    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;
        
    

当我调用它时,我希望收到整个层次结构,其中包含 3 个唯一对象实例(一个用于“节点 A”、“节点 B”、“节点 C”)。

但似乎我有 4 个不同的对象,是对象 A 的两倍。

由于我的班级不是AsReferenceDefault,我有点担心它看不出它与它得到的对象不是同一个对象。

就我而言,我有一个非常大的商业模式(约 500 种不同的模式),它们都继承自同一个根类。每个类都可以在技术上(从模型的角度)被另一个引用,很明显每个类都是唯一的所有者,而其他的只是引用它。 这是我可以用 protobuf 做的事情吗?

因为即使我不知道使用引用时幕后发生了什么,我也有点担心这意味着每个字段都放置了一个唯一的 ID,即使它们没有被引用

编辑

事实上,即使在ProtoContract 上设置AsReferenceDefault = true,我仍然得到4 个对象而不是3 个,现在我有点迷失了。

编辑 2

我确实做了另一个测试,我尝试了一个 Container 类(我的不同操作现在返回一些 Task&lt;Container&lt;Node&gt;&gt;。这个 Container 只包含一个标记为 AsReference = true 的属性。现在它可以工作了,我只有 3实例。

但似乎暗示我没有正确理解AsReference 机制。我在想可能有一个对象的“所有者”,它没有用AsReference=true 标记,所有其他也引用这个对象的对象都是AsReference =true。但如果我理解正确,这将导致有 2 个不同的实例?

如果是,我不明白设置AsReference = true 相对于AsReferenceDefault 的优势?

我理解正确吗?

【问题讨论】:

@MarcGravell 你有没有机会检查这个错误。我们还有很多其他情况,设置 AsReferenceDefault=true 是不够的。 【参考方案1】:

在我看来,这个问题与this question 类似,我们意识到根级实体存在问题。

我们还拥有的是,对于子对象,引用正确,但如果再次引用根项目,则在反序列化后存在副本。

我们使用了一段时间(然后我们切换到纯 JSON)的解决方法是添加一个额外的根节点。使用这个额外的根节点引用正确反序列化。因此,这可能是您也可以尝试的解决方法。

【讨论】:

是的,这就是我所做的,但它并没有真正解决或让我理解它为什么会这样 据我了解,这是 Protobuf 中的一个错误,但我还无法说服 @MarcGravel,他也对这个问题发表了评论。我们真的应该跟进。 我在 github 上查找了现有问题,但没有找到。我在 github 上创建了一个新的 issue。如果缺少某些内容(或错误),请添加您的 cmets。 你好;谢谢-我看到了问题,也看到了赏金-我只是没有时间深入研究它;不过,它在我的清单上非常值得一看,而且我已经回复了 git 帖子。以防万一@J4N 认为他们浪费了一笔赏金:你没有 - 我看到它并理解它导致了问题,所以:“收到消息” - 但我在过去几天根本没有空位。 @MarcGravell Ahah 没问题,只是我们这里有 4 个人等着我去实现 WCF 中的所有 .Net 远程服务,我想知道我们必须做的一切是否可以使用 protobuf还是有问题阻止我们使用它。 (而且我真的不在乎赏金;))

以上是关于如何避免在 protobuf 上的 WCF 中有重复的对象的主要内容,如果未能解决你的问题,请参考以下文章

ProtoBuf WCF“未分配模型实例”

WCF Rest 服务和 protobuf-net

WCF use ProtoBuf

在 WCF 服务中使用 protobuf

带有 Protobuf-net 的端点行为配置 WCF

Protobuf字符串到可读字符串?