【问题标题】:WCF Data Contract with Hierarchical Data in Object GraphWCF 数据契约与对象图中的分层数据
【发布时间】:2023-04-10 10:20:01
【问题描述】:

我正在编写 WCF 服务以从 Active Directory 返回有关人员的信息。除了返回此人的详细信息,我还希望它返回其经理的用户名和全名。

我开始将其编码为:...

[DataContract]
public class ADPerson
{
    Guid objectGuid;
    Guid managerObjectGuid;
    string username;
    string displayname;

    [DataMember]
    public string Username 
    { 
        get { return this.username; }
        set { this.username = value; }
    }
    [DataMember]
    public string DisplayName
    { 
        get { return this.displayName; }
        set { this.displayName = value; }
    }
    [DataMember]
    public ADPerson Manager
    { 
        get { return new ADPerson(this.managerObjectGuid); }
        set { this.managerObjectGuid = value.objectGuid; }
    }

    /* ... */

}

...但后来意识到这没有停止条件;即,它将一直遍历对象图,直到到达未定义经理的用户(即 CEO)。

有没有一种很好的方法来设置这个停止条件,同时仍然能够重用 ADPerson 类,或者我是否需要提供另一种获取经理详细信息的方法(例如,将我希望显示的那些详细信息放入他们自己的字段并从 Manager 属性中删除 DataMember,或者创建一个 ADManager 类来呈现不是经理的经理的 ADPerson 字段的子集?

这是解决问题很简单的另一种情况,但知道问题的最佳解决方案是什么让我很烦恼。

提前致谢,

JB

【问题讨论】:

  • 包括所有最高层的经理并不是最糟糕的包含模式。它应该产生可接受的数字。
  • 没错,在最坏的情况下,深度可能只有 20 人左右,但我喜欢保持相对紧凑(即,将 80% 的内容作为冗余信息返回并不理想 - 我'如果可能的话,宁愿只有被请求的员工和他们的经理)。

标签: c# wcf hierarchical-data datacontract datamember


【解决方案1】:

鉴于循环引用,在 XML 中使用继承必然会变得混乱(“员工 A 有经理 B,要打印经理 B,您必须打印他的员工,其中之一是员工 A... ")。

这段代码表明,使用 DataContractSerializer,这将不起作用:

[ServiceContract]
public class NestedDataService
{
    [OperationContract]
    public Person FindPerson()
    {
        var person = new Person { Name = "E.M. Ployee" };
        var manager = new Person { Name = "M.A. Nager" };

        manager.Employees = new List<Person>();
        manager.Employees.Add(person);

        person.Manager = manager;

        return person;
    }
}

[DataContract]
public class Person
{
    [DataMember]
    public String Name { get; set; }

    [DataMember]
    public Person Manager { get; set; }

    [DataMember]
    public List<Person> Employees { get; set; }
}

我会使用 AD 中的一些 (the?) G/UUID 并使用该 ID 在客户端将它们重新链接在一起。那么员工 A 将不再有 public ADPerson Manager 属性(或者至少就序列化程序而言没有),而是可以像这样实现的 public UUID ManagerID

public UUID ManagerID 
{ 
    get 
        { 
            return Manager != null ? Manager.UUID : null;
        }
}

这限制了您返回一个人,因为如果有与请求的人相关的人,您必须发送ADPersons 的列表,以便能够查找他们。

【讨论】:

  • @HenkHolterman 我遇到过几次这个问题。请参阅已编辑的问题。显示的代码将(至少在默认设置下)在无限循环时破坏 XmlSerializer 和 DataContractSerializer。
  • 有道理,但这将意味着多个 WCF 调用 - 即一个来获取个人,第二个获取他们的经理。由于网络是最慢的部分,我希望减少通话次数。或者,如果从单个调用返回对象列表(即,而不是序列化为层次结构,我按顺序返回所有人,然后将它们绑定在客户端代码中),我需要放入备用逻辑来仅选择我的记录感兴趣,这似乎增加了复杂性?
【解决方案2】:

在我看来,根据给出的信息,最好的解决方案是让你想要序列化的属性在手头的类上可见,并从管理器中删除 DataMember 属性,如下所示:

[DataContract] 
public class ADPerson 
{ 
    Guid objectGuid; 
    Guid managerObjectGuid; 
    string username; 
    string displayname; 

    [DataMember] 
    public string Username  
    {  
        get { return this.username; } 
        set { this.username = value; } 
    } 
    [DataMember] 
    public string DisplayName 
    {  
        get { return this.displayName; } 
        set { this.displayName = value; } 
    } 
    public ADPerson Manager 
    {  
        get { return new ADPerson(this.managerObjectGuid); } 
        set { this.managerObjectGuid = value.objectGuid; } 
    } 
    [DataMember] 
    public string ManagerUsername
    {  
        get { return this.Manager.Username; } 
    } 
    [DataMember] 
    public string ManagerName
    {  
        get { return this.Manager.DisplayName; } 
    } 
} 

如果您不想让他们成为public,他们甚至不必是。

【讨论】:

  • 谢谢 Mike - 这符合我最初的假设/有道理。
  • @JohnLBevan,很高兴能为您提供帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 2011-04-09
  • 2011-01-25
相关资源
最近更新 更多