【问题标题】:Selectively read part of JSON data using JsonSerializer and populate a c# object使用 JsonSerializer 选择性地读取部分 JSON 数据并填充 c# 对象
【发布时间】:2015-09-28 20:09:55
【问题描述】:

我连接到第 3 方 Web 服务,该服务返回一个复杂的 JSON 对象,该对象仅包含我实际需要的少量信息。

基本上,我只需要“值”中的数组。从那个数组中,我只需要“Id”、“Title”和“Status”属性。

我想将这些属性放入一个名为 Project 的 c# 类中。这是我的课:

public class Project
{
    public String Id { get; set; }
    public String Title { get; set; }
    public String Status { get; set; }
}

我正在尝试使用此代码来读取 JSON 并进行转换:

using (WebResponse response = request.GetResponse())
{
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        var serializer = new JsonSerializer();
        var jsonTextReader = new JsonTextReader(reader);
        returnValue = serializer.Deserialize<Project>(jsonTextReader);
    }
}

示例 JSON:

{
    "odata.metadata":"http://school.edu/Api/1/$metadata#Projects",
    "odata.count":"3",
    "value":[
        {
            "odata.id":"http://school.edu/Api/1/Projects('123')",
            "RelatedProjects@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('123')/RelatedProjects",
            "Tags@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('123')/Tags",
            "TimedEvents@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('123')/Categories",
            "ep@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('123')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('123')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('123')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/123"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('123')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('123')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('123')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('123')/AddEP"
                      },
            "Id":"123",
            "Title":"Test Title 1",
            "Status":"Viewable"
        },
        {
            "odata.id":"http://school.edu/Api/1/Projects('456')",
            "RelatedProjects@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('456')/RelatedProjects",
            "Tags@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('456')/Tags",
            "TimedEvents@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('456')/Categories",
            "ep@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('456')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('456')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('456')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/456"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('456')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('456')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('456')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('456')/AddEP"
                      },
            "Id":"456",
            "Title":"Test Title 2",
            "Status":"Viewable"
        },
        {
            "odata.id":"http://school.edu/Api/1/Projects('789')",
            "RelatedProjects@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('789')/RelatedProjects",
            "Tags@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('789')/Tags",
            "TimedEvents@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('789')/Categories",
            "ep@odata.navigationLinkUrl":"http://school.edu/Api/1/Projects('789')/ep",
            "#CreateLike":{
                    "target":"http://school.edu/Api/1/Projects('789')/CreateLike"
                  },
            "#CreateShortcut":{
                        "target":"http://school.edu/Api/1/Projects('789')/CreateShortcut"
                      },
            "#Play":{
                        "target":"http://school.edu/Play/789"
                      },
            "#SendInvitation":{
                        "target":"http://school.edu/Api/1/Projects('789')/SendInvitation"
                      },
            "#CopyProject":{
                        "target":"http://school.edu/Api/1/Projects('789')/CopyProject"
                      },
            "#AddVideoPodcast":{
                        "target":"http://school.edu/Api/1/Projects('789')/AddVideoPodcast"
                      },
            "#AddEP":{
                        "target":"http://school.edu/Api/1/Projects('789')/AddEP"
                      },
            "Id":"789",
            "Title":"Test Title 3",
            "Status":"Viewable"
        }
  ],
  "odata.nextLink":"http://school.edu/Api/1/Folders('xyz')/Projects?$skip=10&$top=10"
}

我只是得到一个空对象。但在调试器中,我可以看到它正在从 web 服务中提取所有 JSON 数据。

如何从 JSON 中获取我需要的内容,构建我的 c# 对象,而忽略其他所有内容?

【问题讨论】:

  • 查看了反序列化文档后,似乎没有此功能的固有功能。因此,为了花时间等待答案,你能不反序列化整个事情,然后选择性地使用你需要的属性吗?
  • @m.edmondson 谢谢。愚蠢的问题,但如果没有反序列化,我将如何获得我需要的数据/属性?
  • 你不能反序列化整个响应吗?
  • 当我执行以下操作时,我可以在调试器中看到它: var rawJson = new StreamReader(response.GetResponseStream()).ReadToEnd();这给了我一个巨大的 JSON 字符串。

标签: c# json parsing json.net


【解决方案1】:

如果你可以使用Json.NET(Newtonsoft json),你可以像这样使用Linq-to-Json [1]

//using Newtonsoft.Json.Linq;
var jsonString = File.ReadAllText(@"C:YourDirectory\file.json"); //source
var projects = new List<Project>(); //Your result

JObject data = JObject.Parse(jsonString);
foreach (var value in data["value"])
{
    projects.Add(new Project
    {
        Id = value["Id"].ToString(),
        Status = value["Status"].ToString(),
        Title = value["Title"].ToString()
    });
}

或者,您也可以像这样反序列化JObject [2]

var jsonReader = data["value"].CreateReader();
projects = new JsonSerializer().Deserialize<List<Project>>(jsonReader);

两者都可以,但哪个更好?

第二种方法意味着更少的代码(特别是,如果Project 类中有许多属性,则必须编写多行代码来映射代码 [1] 中的每个属性)。

但是第一种方法的性能要好很多倍!对于给定的 json 数据,代码 [1] 的运行时间大约为 1 毫秒,而代码 [2] 的运行时间超过 100 毫秒


更新

James Newton-King(编写 Json.NET :) 的输入之后,还有另一种更优雅的方法 [3]

projects = data["value"].ToObject<List<Project>>();

你猜怎么着!这段代码 [3] 花费了接近 [1] 的时间几乎 一半。所以,从各个角度来看,这一定是最好的方法!

【讨论】:

  • 你的第二个例子可以改进:data["value"].ToObject>()
  • @JamesNewton-King 啊!我不知道,谢谢。我已经更新了我的答案以包含它,并且它还根据我的秒表测试显示了最佳性能:)
猜你喜欢
  • 2022-11-25
  • 1970-01-01
  • 2010-12-01
  • 2015-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-02-18
  • 1970-01-01
相关资源
最近更新 更多