使用Newtonsoft将JSON反序列化为.NET对象(也许是LINQ到JSON?)


318

我知道有一些关于Newtonsoft的帖子,所以希望这不是重复...我正在尝试将Kazaa API返回的JSON数据转换为某种不错的对象

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(reader.Read().ToString());

foreach (string item in list)
{
    Console.WriteLine(item);
}

//Console.WriteLine(reader.ReadLine());
stream.Close();

JsonConvert系列只是我正在尝试的最新系列...我不太了解它,希望通过询问大家来消除一些麻烦。我最初试图将其转换为Dictionary或其他内容……实际上,我只需要在那里获取几个值,因此从文档来看,也许Newtonsoft的LINQ to JSON可能是更好的选择?有想法/链接吗?

这是JSON返回数据的示例:

{
  "page": 1,
  "total_pages": 8,
  "total_entries": 74,
  "q": "muse",
  "albums": [
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "http://image.kazaa.com/images/69/01672812 1569/Yaron_Herman_Trio/Muse/Yaron_Herman_Trio-Muse_1.jpg",
      "id": 93098,
      "artist_name": "Yaron Herman Trio"
    },
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "htt p://image.kazaa.com/images/54/888880301154/Candy_Lo/Muse/Candy_Lo-Muse_1.jpg",
      "i d": 102702,
      "artist_name": "\u76e7\u5de7\u97f3"
    },
    {
      "name": "Absolution",
      "permalink": " Absolution",
      "cover_image_url": "http://image.kazaa.com/images/65/093624873365/Mus e/Absolution/Muse-Absolution_1.jpg",
      "id": 48896,
      "artist_name": "Muse"
    },
    {
      "name": "Ab solution",
      "permalink": "Absolution-2",
      "cover_image_url": "http://image.kazaa.com/i mages/20/825646911820/Muse/Absolution/Muse-Absolution_1.jpg",
      "id": 118573,
      "artist _name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Black-Holes-An d-Revelations",
      "cover_image_url": "http://image.kazaa.com/images/66/093624428466/ Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1.jpg",
      "id": 48813,
      "artist_name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Bla ck-Holes-And-Revelations-2",
      "cover_image_url": "http://image.kazaa.com/images/86/ 825646911486/Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1 .jpg",
      "id": 118543,
      "artist_name": "Muse"
    },
    {
      "name": "Origin Of Symmetry",
      "permalink": "Origin-Of-Symmetry",
      "cover_image_url": "http://image.kazaa.com/images/29/825646 912629/Muse/Origin_Of_Symmetry/Muse-Origin_Of_Symmetry_1.jpg",
      "id": 120491,
      "artis t_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz",
      "cover_image_url": "http: //image.kazaa.com/images/68/825646182268/Muse/Showbiz/Muse-Showbiz_1.jpg",
      "id": 60444,
      "artist_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz-2",
      "cover_imag e_url": "http://image.kazaa.com/images/50/825646912650/Muse/Showbiz/Muse-Showbiz_ 1.jpg",
      "id": 118545,
      "artist_name": "Muse"
    },
    {
      "name": "The Resistance",
      "permalink": "T he-Resistance",
      "cover_image_url": "http://image.kazaa.com/images/36/825646864836/ Muse/The_Resistance/Muse-The_Resistance_1.jpg",
      "id": 121171,
      "artist_name": "Muse"
    }
  ],
  "per_page": 10
}

我做了一些阅读,发现Newtonsoft的LINQ to JSON正是我想要的...使用WebClient,Stream,StreamReader和Newtonsoft ...我可以在Kazaa中获取JSON数据,提取URL,下载文件并执行操作就像七行代码一样!我喜欢它。

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

Newtonsoft.Json.Linq.JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());

// Instead of WriteLine, 2 or 3 lines of code here using WebClient to download the file
Console.WriteLine((string)jObject["albums"][0]["cover_image_url"]);
stream.Close();

这篇文章获得了很多点击,我认为包括注释中讨论的“使用”位可能会有所帮助。

using(var client = new WebClient())
using(var stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album"))
using (var reader = new StreamReader(stream))
{
    var jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
    Console.WriteLine((string) jObject["albums"][0]["cover_image_url"]);
}

6
光滑的例子,谢谢。只是一个建议:为简洁起见,您可能省略了此内容,但是由于 和WebClientStream以及StreamReader所有实现IDisposable,您可能想要using在代码中添加一些块。
arcain 2011年

啊,是个好电话...(实际上,这只是一个控制台应用程序,我正在快速运行以快速研究要执行的任务)现在开始研究难题的最后一部分,HLS + AES加密:)嗯...大声笑
本杰明

1
+1感谢您发布Linq示例。正是我需要的。
Mark Wilkins

newtonsoft解决方案是否还没有完全反序列化JSON?就像@arcain的解决方案一样。
AXMIM

请注意此处的链接:LINQ to JSON
洋剑

Answers:


259

如果您只需要从JSON对象中获取一些项,则可以使用Json.NET的LINQ to JSON JObject类。例如:

JToken token = JObject.Parse(stringFullOfJson);

int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");

我喜欢这种方法,因为您不需要完全反序列化JSON对象。API随手可得,有时可能会因缺少对象属性(例如Twitter)而使您感到惊讶。

文档:序列化和反序列化JSON与Json.NETLINQ到JSON与Json.NET


1
是的,我实际上已经做了更多的阅读和测试...发现这也是一种很好的实现方法... Newtonsoft,非常漂亮的库,我将向他人发布示例
J Benjamin

1
发布了一个有关我如何做的粗略示例...不太一样,我看到您建议使用JToken.Parse ...不确定这两者之间的区别,但是很好!
J本杰明

1
@Jbenjamin谢谢!那是一个错字。JToken是JObject的基类,使用更抽象的类型只是我个人的喜好。感谢您提请我注意。
arcain 2011年

抱歉,它应该是JToken还是JObject?上面的代码仍然不时抛出错误“从JsonReader读取JObject时出错”。
TYRONEMICHAEL

1
@Tyrone当然,没问题。实际上,我也使用此代码进行Twitter状态解析,而且由于对Twitter的调用有时可能会显得参差不齐,因此我不得不在调用Twitter周围编写大量错误处理。如果您尚未这样做,建议您在尝试解析之前将Twitter的原始JSON响应转储到日志中。然后,如果失败,您至少可以查看是否通过电线收到了一些时髦的东西。
arcain 2012年

272

您可以使用C#dynamic类型简化事情。由于不依赖魔术字符串,该技术还使重构更加简单。

JSON格式

下面的JSON字符串是来自HTTP API调用的简单响应,它定义了两个属性:IdName

{"Id": 1, "Name": "biofractal"}

C#

用于JsonConvert.DeserializeObject<dynamic>()将该字符串反序列化为动态类型,然后以通常的方式简单地访问其属性。

dynamic results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

如果将results变量的类型指定为dynamic,而不使用var关键字,则属性值将正确反序列化,例如Id,反序列化为an int而不是a JValue(感谢GFoley83的注释)。

注意:Newtonsoft程序集的NuGet链接是http://nuget.org/packages/newtonsoft.json

软件包:您还可以使用nuget live installer添加该软件包,打开项目后只需浏览软件包,然后安装即可安装,卸载,更新,它将被添加到您的项目中Dependencies / NuGet下


我使用与上述相同的代码反序列化newtonsoft.dll 4.5.6版的Twitter响应,并且工作正常..但是将其更新为5.0.6版后..它开始引发错误...任何想法为什么??
普拉纳夫2014年

1
当我们知道或拥有c#类时,对动态对象很有用,因此我们可以在替换动态对象时将其用作C#类,例如<Myclass>。
MSTdev 2015年

2
dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);在这里使用FTW。它将正确反序列化为Idint而不是JValue。看到这里:dotnetfiddle.net/b0WxGJ
GFoley83 '16

@biofractal我将如何dynamic results = JsonConvert.DeserializeObject<dynamic>(json); 在VB.NET中做到这一点?Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)不起作用。
Flo


41

使用dynamic关键字,解析此类对象变得非常容易:

dynamic x = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
var page = x.page;
var total_pages = x.total_pages
var albums = x.albums;
foreach(var album in albums)
{
    var albumName = album.name;

    // Access album data;
}

我想知道如何遍历结果,这花了很长时间才找到...谢谢!
batoutofhell 2016年

22

如果我弄错了,请纠正我,但是我相信前面的示例与James Newton的Json.NET库的最新版本只是有点不同步。

var o = JObject.Parse(stringFullOfJson);
var page = (int)o["page"];
var totalPages = (int)o["total_pages"];

1
感谢您的回复。Rick也很像我在最新文档中找到的示例。
J本杰明

1
是的,自从arcain修正了错字后,我的评论现在看起来很挑剔:'(。我最初发布是因为我不认识JToken.Parse。–
Rick Leitch

1
根本不挑剔-肯定一个错误,而且总是有不止一种方法来做到这一点。顺便说一句,我的Json.NET版本确实支持使用indexer on的语法JObject,但是我为答案修改的代码是从使用该SelectToken方法重载的代码中提取的,因此,如果没有使用令牌,我可以抑制异常found JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch):,所以这是冗长的来源。
arcain 2011年

18

如果像我一样,您喜欢处理强类型对象**,请配合以下方法:

MyObj obj =  JsonConvert.DeserializeObject<MyObj>(jsonString);

这样,您就可以使用智能感知和编译时类型错误检查。

通过将JSON复制到内存中并将其粘贴为JSON对象,您可以轻松创建所需的对象(Visual Studio->编辑->选择性粘贴-> JSON作为类粘贴)。

如果您在Visual Studio中没有该选项,请参见此处

您还需要确保JSON有效。如果只是对象数组,请在开头添加您自己的对象。即{ “ obj”: [{},{},{}]}

**我知道动态有时会使事情变得更容易,但是对此我有点不高兴。


1
我非常喜欢编程的方法。我喜欢强类型的对象。谢谢,因为我使用和修改了这段代码。
j.hull,

11

宽松类型的动态列表 -反序列化并读取值

// First serializing
dynamic collection = new { stud = stud_datatable }; // The stud_datable is the list or data table
string jsonString = JsonConvert.SerializeObject(collection);


// Second Deserializing
dynamic StudList = JsonConvert.DeserializeObject(jsonString);

var stud = StudList.stud;
foreach (var detail in stud)
{
    var Address = detail["stud_address"]; // Access Address data;
}

8

我喜欢这种方法:

using Newtonsoft.Json.Linq;
// jsonString is your JSON-formatted string
JObject jsonObj = JObject.Parse(jsonString);
Dictionary<string, object> dictObj = jsonObj.ToObject<Dictionary<string, object>>();

现在,您可以将dictObj用作字典来访问任何内容。Dictionary<string, string>如果您希望将值作为字符串获取,也可以使用。

您可以使用相同的方法将其转换为任何类型的.NET对象。


2
我发现此方法非常好,其原因有两个:1)当您不关心数据类型(一切都是字符串)时,2)使用值的字典很方便
netfed

7

另外,如果您只是想在JSON内容中嵌套一个特定的值,则可以执行以下操作:

yourJObject.GetValue("jsonObjectName").Value<string>("jsonPropertyName");

依此类推。

如果您不想承担将整个JSON转换为C#对象的开销,这可能会有所帮助。


2

我为json创建了一个Extionclass:

 public static class JsonExtentions
    {
        public static string SerializeToJson(this object SourceObject) { return Newtonsoft.Json.JsonConvert.SerializeObject(SourceObject); }


        public static T JsonToObject<T>(this string JsonString) { return (T)Newtonsoft.Json.JsonConvert.DeserializeObject<T>(JsonString); }
}

设计模式:

 public class Myobject
    {
        public Myobject(){}
        public string prop1 { get; set; }

        public static Myobject  GetObject(string JsonString){return  JsonExtentions.JsonToObject<Myobject>(JsonString);}
        public  string ToJson(string JsonString){return JsonExtentions.SerializeToJson(this);}
    }

用法:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);


1

参加这个聚会还很晚,但是我今天在工作中遇到了这个问题。这是我解决问题的方法。

我正在访问第三方API来检索书籍列表。该对象返回了一个庞大的JSON对象,其中包含大约20多个字段,我只需要ID作为List字符串对象即可。我在动态对象上使用linq检索所需的特定字段,然后将其插入到List字符串对象中。

dynamic content = JsonConvert.DeserializeObject(requestContent);
var contentCodes = ((IEnumerable<dynamic>)content).Where(p => p._id != null).Select(p=>p._id).ToList();

List<string> codes = new List<string>();

foreach (var code in contentCodes)
{
    codes.Add(code?.ToString());
}

0

最后从JSON获取状态名称

谢谢!

Imports System
Imports System.Text
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.collections.generic

Public Module Module1
    Public Sub Main()

         Dim url As String = "http://maps.google.com/maps/api/geocode/json&address=attur+salem&sensor=false"
            Dim request As WebRequest = WebRequest.Create(url)
        dim response As WebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
        dim reader As New StreamReader(response.GetResponseStream(), Encoding.UTF8)
          Dim dataString As String = reader.ReadToEnd()

        Dim getResponse As JObject = JObject.Parse(dataString)

        Dim dictObj As Dictionary(Of String, Object) = getResponse.ToObject(Of Dictionary(Of String, Object))()
        'Get State Name
        Console.WriteLine(CStr(dictObj("results")(0)("address_components")(2)("long_name")))
    End Sub
End Module
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.