使用RestSharp客户端反序列化嵌套的JSON响应

3

我希望能够调用REST API并反序列化嵌套的JSON响应。为此,我尝试创建一些POCO类来表示JSON响应[1]。 响应的格式如下:

{
  "success": true,
  "message": "OK",
  "types": 
  [
    {
      "name": "A5EF3-ASR",
      "title": "ITIL Foundation Plus Cloud Introduction",
      "classroomDeliveryMethod": "Self-paced Virtual Class",
      "descriptions": {
        "EN": {
          "description": "some Text null",
          "overview": null,
          "abstract": "Some other text",
          "prerequisits": null,
          "objective": null,
          "topic": null
        }
      },
      "lastModified": "2014-10-08T08:37:43Z",
      "created": "2014-04-28T11:23:12Z"
    },
    {
      "name": "A4DT3-ASR",
      "title": "ITIL Foundation eLearning Course + Exam",
      "classroomDeliveryMethod": "Self-paced Virtual Class",
      "descriptions": {
        "EN": {
          "description": "some Text"
          (...)

所以我创建了以下POCO类:
public class Course
{
    public bool success { get; set; }
    public string Message { get; set; }
    public List<CourseTypeContainer> Type { get; set; }
}

/* each Course has n CourseTypes */
public class CourseType
{
    public string Name { get; set; }
    public string Title { get; set; }
    public List<CourseTypeDescriptionContainer> Descriptions { get; set; }
    public DateTime LastModified { get; set; }
    public DateTime Created { get; set; }
}
public class CourseTypeContainer
{
    public CourseType CourseType { get; set; }
}


/* each CourseType has n CourseTypeDescriptions */
public class CourseTypeDescription
{
    public string Description { get; set; }
    public string Overview { get; set; }
    public string Abstract { get; set; }
    public string Prerequisits { get; set; }
    public string Objective { get; set; }
    public string Topic { get; set; }
}
public class CourseTypeDescriptionContainer
{
    public CourseTypeDescription CourseTypeDescription { get; set; }
}

以下是 API 代码:

var client = new RestClient("https://www.someurl.com");
client.Authenticator = new HttpBasicAuthenticator("user", "password");

var request = new RestRequest();
request.Resource = "api/v1.0/types";
request.Method = Method.GET;
request.RequestFormat = DataFormat.Json;

var response = client.Execute<Course>(request);

编辑1: 我发现了一个错别字,AvnetCourse中的Type属性应该被命名为Types

public List<AvnetCourseTypeContainer> Type { get; set; }    // wrong
public List<AvnetCourseTypeContainer> Types { get; set; }   // correct

现在返回值看起来像这样:
response.Data.success = true                    // CORRECT
repsonse.Data.Message = "OK"                    // CORRECT
response.Data.Types = (Count: 1234);            // CORRECT
response.Data.Types[0].AvnetCourseType = null;  // NOT CORRECT

编辑 2: 我使用 List<CourseType> 实现了 Course.Types 属性,而不是使用 List<CourseTypeContainer>,这是由Jaanus建议的。对于 CourseTypeDescriptionContainer 也是同样的处理:

public List<CourseTypeContainer> Type { get; set; }                     // OLD
public List<CourseTypeDescriptionContainer> Descriptions { get; set; }  // OLD
public List<CourseType> Type { get; set; }                              // NEW
public List<CourseTypeDescription> Descriptions { get; set; }           // NEW

现在,response.Data.Types的响应数据类型已经被正确填充。然而,由于存在额外的语言层(例如“EN”),response.Data.Types.Descriptions仍未正确填充。我该如何解决这个问题,而不需要为每种语言创建一个PACO? 编辑3:我必须添加一个额外的CourseTypeDescriptionDetails类,在其中存储描述性数据。在我的CourseTypeDescription中,我为每种语言添加了一个类型List的属性。代码片段:
public class AvnetCourseType
{
    public List<CourseTypeDescription> Descriptions { get; set; }
    // other properties
}
public class CourseTypeDescription
{
    public List<CourseTypeDescriptionDetails> EN { get; set; } // English
    public List<CourseTypeDescriptionDetails> NL { get; set; } // Dutch
}
public class CourseTypeDescriptionDetails
{
    public string Description { get; set; }
    public string Overview { get; set; }
    public string Abstract { get; set; }
    public string Prerequisits { get; set; }
    public string Objective { get; set; }
    public string Topic { get; set; }
}

现在它已经可用,但我需要为每种语言添加另一个CourseTypeDescription属性。
旧的:返回值为:
response.Data.success = true            // CORRECT
repsonse.Data.Message = "OK"            // CORRECT
response.Data.Type = null;              // WHY?

那么为什么我的response.Type等于null?我做错了什么吗?

谢谢

资源: [1] 使用JSON数组进行RestSharp反序列化


1
下次您需要基于一些JSON示例的POCO类,请尝试http://json2csharp.com。简单多了:) - Todd Menier
太好了!谢谢。 - Ronin
3个回答

1
尝试使用这个作为 POCO:
public class Course
{
    public bool success { get; set; }
    public string message { get; set; }
    public List<CourseTypeContainer> Types { get; set; }
}

现在您有一个 CourseTypeContainer 列表。 而 CourseTypeContainer 是什么。
public class CourseTypeContainer
{
    public CourseType CourseType { get; set; }
}

当您尝试获取response.Data.Types[0].AvnetCourseType时,需要在CourseTypeContainer内部具有AvnetCourseType字段。
或者我认为您实际上想要的是这个公共List<CourseType> Types { get; set; },您不需要一个容器。

谢谢,我也自己找到了打字错误 :) 我更新了我的问题。现在它会列出所有类型,但这些都是空的(null)。我的代码有什么问题? - Ronin
你能检查一下response.Data.Types中有多少个元素,这样我们就知道他是否至少得到了一些东西。 - Jaanus
是的,它确实获取了一些东西。有超过2k个response.Data.Types元素,但它们全部为null。 - Ronin
移除容器,只使用CourseType列表。 - Jaanus
哇,当我使用List<CourseType> Types时真的有效!! :D 非常感谢!!您能解释一下,在哪种情况下我需要一个容器吗? - Ronin
让我们在聊天中继续这个讨论 - Ronin

0

我使用http://json2csharp.com/从JSON创建C#类。 然后,将RootObject重命名为我正在创建的模型文件的ClassName 在RestSharp反序列化后,所有嵌套JSON中的数据都可以访问,类似于responseBody.data.Subject.Alias 其中data、Subject和Alias是响应JSON中的嵌套节点。


0

仅供参考,如果对其他人有帮助的话。我尝试了这里提到的所有方法,但在当前版本的RestSharp(106.6.2)上仍然无法正常工作。据我所知,RestSharp完全忽略了RootElement属性,即使它在顶层。我的解决方法是手动告诉它提取嵌套的JSON,然后转换它。我使用了JSON.Net来实现这一点。

var response = restClient.Execute<T>(restRequest);
response.Content = JObject.Parse(response.Content)[restRequest.RootElement].ToString();
return new JsonDeserializer().Deserialize<T>(response);

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