JSON反序列化困境(无法反序列化嵌套类型)

3

在 Stack Overflow 上可能有 500 个类似的问题,还有无数网站提供信息 - 但我只是看不清楚。这似乎应该是非常简单的操作,但我就是做不到。

我有一个返回序列化 JSON 对象的 WCF Web 服务:

[OperationContract(Name = "PeopleData"), WebGet(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "people/{subset}", ResponseFormat = WebMessageFormat.Json)]
PeopleObject GetPeople(string subset);

这个有效——如果我在浏览器中输入该URI,将调用GetPeople并返回一个JSON序列化的PeopleObject(这里为了隐私而实际数据值被省略):

{"HashValue":"XXXXX","People":[{"EmailAddress":"XXXXX","EmployeeID":99999,"Gender":"X","JobTitle":"XXXXX","Office":"","PreferredName":"XXXXX","Surname":"XXXXX","WorkExtensionNumber":"XXXXX","WorkPhoneNumber":"XXXXX","Department":"XXXXX","DeskNumber":"XXXXX","EmploymentClassification":"XXXXX","InternationalExtensionNumber":"XXXXX","IsFirstAider":false,"Languages":[{"LanguageID":9,"LanguageSkillID":9},{"LanguageID":9,"LanguageSkillID":9}],"QualificationInitials":"XXXXX","QualificationTitle":"XXXXX","Secretaries":null,"WorkMobilePhoneNumber":"XXXXX"}],"RecordCount":"1","SizeBytes":"12345"}

在这个例子中,PeopleObject负载只包含一个Person对象在集合中,但根据/{subset}中提供的参数,可能包含许多对象。
下面是PeopleObject的类层次结构 - 它是一个顶级容器,包含有关负载的一些元数据,以及Person对象的List<>。这些对象又有一堆简单类型属性,以及两个进一步嵌套的List<>,其中包含LanguageSecretary对象(可能填充或未填充):
  [DataContract]
  public class PeopleObject
  {
    [DataMember]
    public string HashValue { get; set; }
    [DataMember]
    public List<Person> People { get; set; }
    [DataMember]
    public string RecordCount { get; set; }
    [DataMember]
    public string SizeBytes { get; set; }
  }

  [DataContract]
  public class Person
  {
    [DataMember]
    public string EmailAddress { get; set; }
    // <-- snip - lots of fields like this, no point listing them all here
    [DataMember]
    public bool IsFirstAider { get; set; }
    [DataMember]
    public List<Language> Languages { get; set; }
    [DataMember]
    public List<Secretary> Secretaries { get; set; }
  }

  [DataContract]
  public class Language
  {
    [DataMember]
    public int LanguageID { get; set; }
    [DataMember]
    public int LanguageSkillID { get; set; }
  }

  [DataContract]
  public class Secretary
  {
    [DataMember]
    public int EmployeeID { get; set; }
    [DataMember]
    public char FirstSurnameLetter { get; set; }
  }

目前为止,WCF以JSON结构响应并包含所有字段及其内容。现在需要在客户端应用程序中反序列化该结构(使用相同的类层次结构定义):

  // I have a little helper-class to manage the WCF request and return a Stream
  using (Stream response = wcfHelper.GetRequestResponseStream(MY_WCF_URI))
  {
    // This is debug code to prove the response arrives as expected - it does
    //StreamReader sr = new StreamReader(response);
    //Console.WriteLine("\nResponse:\n{0}", sr.ReadToEnd());

    // Deserialise the response
    DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(PeopleObject));
    PeopleObject p = (PeopleObject)dc.ReadObject(response);

    // The object shows 1 record (in the example) but nothing in the List<>
    Console.WriteLine("\nDeserialized records: '{0}' [{1}]", p.RecordCount, p.People.Count);
  }

这样做可以正确反序列化容器对象,以给出记录计数、哈希值和有效载荷大小(以字节为单位)。该对象还具有一个Person对象的List<>,但它是null——来自JSON响应的内容未能通过创建和添加Person对象成功地重新生成List<>。

我错过了什么?我的理解是,从JSON结构中重新生成C#对象层次结构应该自动发生,所以要么不是这种情况(我需要编写一些代码使其发生),要么就是,但我错过了一些显而易见的东西。


1
瞎猜一下:“枚举类型可以标记为DataContractAttribute属性,这样参与序列化的每个成员都必须标记EnumMemberAttribute属性。未标记的成员不会被序列化。” http://msdn.microsoft.com/en-us/library/ms731923.aspx - jbabey
@jbabey 我认为这是指“枚举”类型,而不是像List<T>这样的可枚举类型。 - Chris Sinclair
1
您需要提供所有子类型的列表。请参考:http://msdn.microsoft.com/zh-cn/library/bb908209.aspx - crush
1个回答

1

我以前没有做过你正在做的事情,但根据文档的说明,我认为以下内容会起作用:

List<Type> types = new List<Type>();
types.Add(typeof(Person));
types.Add(typeof(Language));
types.Add(typeof(Secretary));

DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(PeopleObject), types);
PeopleObject p = (PeopleObject)dc.ReadObject(response);

你需要告诉序列化器在序列化/反序列化对象时可能遇到的所有类型。

操! 没错,干得漂亮。 你很棒。 - Eight-Bit Guru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接