使用 Newtonsoft 将 JSON 反序列化为 .NET 对象(或者可能是 LINQ to JSON?)
Posted
技术标签:
【中文标题】使用 Newtonsoft 将 JSON 反序列化为 .NET 对象(或者可能是 LINQ to JSON?)【英文标题】:Deserializing JSON to .NET object using Newtonsoft (or LINQ to JSON maybe?) 【发布时间】:2011-06-12 14:06:07 【问题描述】:我知道有一些关于 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 线只是我最近尝试的一条……我不太明白,希望通过询问你们来消除一些步法。我最初试图将它转换成字典或其他东西......实际上,我只需要在那里获取几个值,所以从文档来看,也许 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();
这篇文章获得了很多点击,我认为包含 cmets 中讨论的“使用”位可能会有所帮助。
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"]);
【问题讨论】:
漂亮的例子,谢谢。只是一个建议:为简洁起见,您可能已将其关闭,但由于WebClient
、Stream
和 StreamReader
都实现了 IDisposable
,您可能需要在代码中添加一些 using
块。
啊,是的,很好的电话......(是的,这实际上只是一个控制台应用程序,我正在快速运行以研究我即将完成的任务)现在开始研究最后一块拼图, HLS+AES 加密 :) 呃...大声笑
newtonsoft 解决方案是否也没有完全反序列化 JSON?就像@arcain 的解决方案一样。
注意这里的链接:LINQ to JSON
【参考方案1】:
您可以使用 C# dynamic
类型来简化操作。这种技术还使重构更简单,因为它不依赖于魔法字符串。
JSON
下面的 JSON 字符串是来自 HTTP API 调用的简单响应,它定义了两个属性:Id
和 Name
。
"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
到 int
而不是 JValue
(感谢 GFoley83 在下面的评论)。
注意:Newtonsoft 程序集的 NuGet 链接是 http://nuget.org/packages/newtonsoft.json。
包:您也可以使用 nuget live 安装程序添加包,打开您的项目只需执行browse package 然后安装它install, unistall, update,它只会添加到您的项目中依赖项/NuGet
【讨论】:
我使用与上面相同的代码来反序列化带有 newtonsoft.dll 版本 4.5.6 的 twitter 响应,它工作正常..但是在将其更新到版本 5.0.6 .. 它开始抛出错误......知道为什么吗?? 适用于动态对象,当我们知道或我们有 c# 类时,我们可以在替换动态时作为 C# 类使用,例如. 在这里使用dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);
FTW。它将正确地将Id
反序列化为int 而不是JValue
。见这里:dotnetfiddle.net/b0WxGJ
@biofractal 我将如何在 VB.NET 中执行此操作 dynamic results = JsonConvert.DeserializeObject<dynamic>(json);
? Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)
不起作用。
@Flo 试试...DeserializeObject(Of System.Dynamic.ExpandoObject).【参考方案2】:
如果您只需要从 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。
文档:Serializing and Deserializing JSON with Json.NET 和 LINQ to JSON with Json.NET
【讨论】:
是的,我实际上已经做了更多的阅读和测试......发现这也是一种很好的方法......Newtonsoft,非常好的图书馆,我会发布我的例子为他人 发布了一个粗略的例子来说明我是如何做到的...不太一样,我看到你建议使用 JToken.Parse...不确定两者之间的区别,但是你,好东西! @Jbenjamin 谢谢!那是一个错字。 JToken 是 JObject 的基类,使用更抽象的类型只是我个人的偏好。感谢您提醒我注意。 抱歉,应该是 JToken 还是 JObject?上面的代码仍然不时抛出错误“Error reading JObject from JsonReader”。 @Tyrone 当然,没问题。实际上,我也将此代码用于 Twitter 状态解析,并且我不得不围绕对 Twitter 的调用编写相当多的错误处理,因为它们有时可能参差不齐。如果您还没有这样做,我建议您在尝试解析之前将原始 JSON 响应从 Twitter 转储到日志中。然后,如果它失败了,你至少可以看看你是否通过电线收到了一些时髦的东西。【参考方案3】:使用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;
【讨论】:
我想知道如何循环查看结果,但找到的时间太长了...谢谢!!【参考方案4】:如果我弄错了,请纠正我,但我相信前面的示例与 James Newton 的 Json.NET 库的最新版本略有不同步。
var o = JObject.Parse(stringFullOfJson);
var page = (int)o["page"];
var totalPages = (int)o["total_pages"];
【讨论】:
感谢您的回复 Rick,您的回复看起来也与我在最新文档中找到的示例相似。 是的,因为 arcain 修正了错字,我的评论现在看起来很挑剔:'(。我最初发布是因为我不认识 JToken.Parse。 一点也不挑剔——肯定有是错误,而且总是有不止一种方法可以做到这一点。顺便说一句,我的 Json.NET 版本确实支持使用JObject
上的索引器的语法,但是我为我的答案修改的代码是从使用SelectToken
方法的重载的代码中提取的,因此我可以抑制异常如果找不到令牌:JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch)
,这就是冗长的来源。【参考方案5】:
如果您像我一样喜欢处理强类型对象**,请选择:
MyObj obj = JsonConvert.DeserializeObject<MyObj>(jsonString);
这样您就可以使用智能感知和编译时类型错误检查。
您可以通过将 JSON 复制到内存中并将其粘贴为 JSON 对象(Visual Studio -> 编辑 -> 选择性粘贴 -> 将 JSON 粘贴为类)来轻松创建所需的对象。
如果您在 Visual Studio 中没有该选项,请参阅 here。
您还需要确保您的 JSON 有效。如果它只是一个对象数组,请在开始时添加您自己的对象。即 "obj":[,,]
** 我知道 dynamic 有时会让事情变得更容易,但我对此有点过分。
【讨论】:
非常喜欢的编程方法。我喜欢强类型的对象。谢谢,因为我使用并修改了这段代码。 粘贴到 JSON 功能的东西太棒了!为我节省了大量时间【参考方案6】:动态列表松散类型 - 反序列化并读取值
// 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;
【讨论】:
【参考方案7】:我喜欢这种方法:
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 对象。
【讨论】:
我觉得这个方法非常好,有两个原因:1)当你不关心数据类型时(一切都是字符串),2)使用值字典很方便跨度> 【参考方案8】:此外,如果您只是在寻找嵌套在 JSON 内容中的特定值,您可以执行以下操作:
yourJObject.GetValue("jsonObjectName").Value<string>("jsonPropertyName");
从那里开始等等。
如果您不想承担将整个 JSON 转换为 C# 对象的成本,这可能会有所帮助。
【讨论】:
【参考方案9】:我为 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);
【讨论】:
***.com/questions/2246694/…【参考方案10】:参加这个聚会已经很晚了,但我今天在工作中遇到了这个问题。这是我解决问题的方法。
我正在访问第 3 方 API 以检索书籍列表。该对象返回一个包含大约 20 多个字段的大型 JSON 对象,其中我只需要将 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());
【讨论】:
codes.Add(code?.ToString())
将为任何缺失的代码添加一个空值。 ?
不在可以阻止 codes.Add
执行的位置。你可能想要if (code != null) ...
【参考方案11】:
最终从 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
【讨论】:
【参考方案12】:使用 JsonConvert.DeserializeObject() 函数进行反序列化
public class ApiValues
[JsonProperty("Address")]
public string Address get; set;
[JsonProperty("BaseUrl")]
public string BaseUrl get; set;
var json =
"Address":"some-address",
"BaseUrl":"some-url-value"
var values = JsonConvert.DeserializeObject<ApiValues>(json);
【讨论】:
以上是关于使用 Newtonsoft 将 JSON 反序列化为 .NET 对象(或者可能是 LINQ to JSON?)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Newtonsoft 将 JSON 反序列化为 .NET 对象(或者可能是 LINQ to JSON?)
如何使用 NewtonSoft Json.Net 将 Json 字典反序列化为平面类
Newtonsoft 反序列化到对象存储底层 JSON 作为属性