如何使用C#反序列化JSON数据?

558
我有以下的代码:
var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);

输入的responsecontent是JSON格式的,但是没有正确地反序列化为一个对象。我应该如何正确地反序列化它?

7
你可以尝试这个链接:http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html,它教你如何编写自己的JSON解析器。 - Vamsi
47
System.Web.Helpers中有Json,在System.ServiceModel.Web中有JsonQueryStringConverter,在System.Web.Script.Serialization中有JavascriptSerializer,在System.Runtime.Serialization.Json中有DataContractJsonSerializer,甚至MS都决定在其ASP.NET Web API中包括第三方Json.NET。如果你觉得这还不够,MS正在开发System.Json,但目前不适合使用。微软太棒了,我选择最好看的命名空间。 - nawfal
@nawfal 在 .net4.5 中我只找到了 System.Runtime.Serialization.Json 中的 DataContractJsonSerializer。 - fusi
4
@fusi 其余的部分被分成了不同的程序集。在谷歌上搜索命名空间/类名,你会找到它们所在的程序集MSDN文档。只需添加对该程序集的引用即可。 - nawfal
1
只是为了完整性,Windows.Data.Json 中还有 JsonValue,仅适用于 Windows 8 及以上版本。我很喜欢它。微软正在使命中 :) - nawfal
6
NewtonSoft 在其网站上提供了一个比较页面(可能有偏见但仍然很有趣):http://www.newtonsoft.com/json/help/html/jsonnetvsdotnetserializers.htm。我特别喜欢“无意义的词典序列化”这一行 :) - Ohad Schneider
19个回答

431

我假设您没有使用Json.NET库(Newtonsoft.Json NuGet包)。如果是这种情况,那么您应该尝试一下它。

它具有以下功能:

  1. LINQ to JSON
  2. JsonSerializer可以快速将您的.NET对象转换为JSON格式,反之亦然
  3. Json.NET可选地生成格式良好、缩进的JSON代码,方便调试或显示
  4. 可以向类中添加属性,如JsonIgnoreJsonProperty,以自定义序列化方式
  5. 能够将JSON与XML相互转换
  6. 支持多个平台:.NET、Silverlight以及Compact Framework

请查看下面的示例。在此示例中,JsonConvert类用于将对象转换为JSON格式并从JSON格式反序列化为对象,它有两个静态方法:SerializeObject(Object obj)DeserializeObject<T>(String json)

using Newtonsoft.Json;

Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string json = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "Expiry": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);

22
我能否将反序列化到“var”类型的变量中,在我不知道目标的完整结构的情况下?具体来说,我正在使用Rally用户故事,并希望将它们转换为对象。 - Pedro Dusso
1
@PedroDusso,你可以的,这里是完整的文档 - Gun2sh
3
@PeterWone说:"不是的,JSON.parse('{"Expiry": "2008-12-28T00:00:00"}').Expiry 返回的是 字符串 "2008-12-28T00:00:00",而不是日期。可以通过 new Date(str) 将其转换为 Date,但是 JSON.parse 对日期一无所知。你需要传入一个检查每个字符串值是否符合模式的reviver。" - T.J. Crowder
@T.J.Crowder 我对JSON.stringify(new Date())的测试在Microsoft Edge上产生了"2015-09-28T01:08:03.704Z",而new Date(JSON.stringify(new Date()))则出现了错误。 - Peter Wone
3
由于3.703秒与3秒和703毫秒相同,并且分隔符为小数点,因此我向您提出这是三位小数的秒数。 - Peter Wone
显示剩余5条评论

364

正如在这里回答的那样 - 将JSON反序列化为C#动态对象?

使用Json.NET相当简单:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

或者使用Newtonsoft.Json.Linq:

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

14
@MaxHodges,你是正确的。我只是使用内联的“Magic Strings”来演示如何解析JSON字符串值。不想通过转义双引号使其看起来复杂。在真实代码中,我们通常会将JSON字符串作为变量从某个地方获取或作为参数传递。 - Dmitry Pavlov
5
如果没有 .net 4,就不能使用 'dynamic' 关键字。你可以使用 'var stuff' 来声明,而不是使用 'stuff.Name' 和 'stuff.Address.City',而是分别使用 'stuff["Name"]' 和 'stuff["Address"]["City"]'。 - Fil
3
这将给你一个类型为“object”的值,你无法在一个“object”上使用索引。 - Alex
@Alex 我很确定 Newtonsoft.Json 变量返回一个 JObject。另外,不要使用 Json.NET,因为现在连 VS 都使用 Newtonsoft.Json 了。甚至可以在 VSIX 中使用,而无需将其添加到包中。 - Patrick Beynio

156

以下是一些不使用第三方库的选项:

// For that you will need to add reference to System.Runtime.Serialization
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }"), new System.Xml.XmlDictionaryReaderQuotas());

// For that you will need to add reference to System.Xml and System.Xml.Linq
var root = XElement.Load(jsonReader);
Console.WriteLine(root.XPathSelectElement("//Name").Value);
Console.WriteLine(root.XPathSelectElement("//Address/State").Value);

// For that you will need to add reference to System.Web.Helpers
dynamic json = System.Web.Helpers.Json.Decode(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }");
Console.WriteLine(json.Name);
Console.WriteLine(json.Address.State);

请查看链接以获取有关 System.Web.Helpers.Json 的更多信息。

更新: 如今获取 Web.Helpers 最简单的方法是使用 NuGet 包


如果您不关心早期的 windows 版本,可以使用 Windows.Data.Json 命名空间中的类:

// minimum supported version: Win 8
JsonObject root = Windows.Data.Json.JsonValue.Parse(jsonString).GetObject();
Console.WriteLine(root["Name"].GetString());
Console.WriteLine(root["Address"].GetObject()["State"].GetString());

1
为什么我在我的ASP.NET网站(4.5)中看不到System.Web.Helpers?XElement,XPathSelectElement在我的VisualStudio中也不被识别。如何让它识别? - Budda
2
我使用了这里描述的Web.Helpers方法,但遇到了一个问题,这个帖子解决了我的问题:https://dev59.com/S2w05IYBdhLWcg3wuUKY - Alex
位于 #region Assembly System.ServiceModel.Web.dll,v3.5.0.0,+ System.Runtime.Serialization.dll + System.XML.dll。 - Evalds Urtans
1
它可以与WPF一起使用。通过使用以下命名空间: using System.Runtime.Serialization.Json; using System.Xml.XPath; using System.Xml.Linq; - Shahid Neermunda
4
Json.Net现在已经不再是一个第三方组件了。微软自己也在使用它。它是Web API的默认序列化器。 - Liam
显示剩余5条评论

66

如果你可以使用.NET 4,请查看:http://visitmix.com/writings/the-rise-of-json(archive.org)

以下是该网站的一部分:

WebClient webClient = new WebClient();
dynamic result = JsonValue.Parse(webClient.DownloadString("https://api.foursquare.com/v2/users/self?oauth_token=XXXXXXX"));
Console.WriteLine(result.response.user.firstName);

那个最后的 Console.WriteLine 很不错...


抱歉,看起来自我最初回答以来情况已经发生了变化。我需要四处查找并确定哪个库是正确的... - ElonU Webdev
7
期待您找到这个库。编辑:它是这个吗:http://dynamicjson.codeplex.com/? - user989056
1
我不知道ElonU在这里指的是什么类,但是在Windows.Data.Json中有“JsonValue”(仅适用于Windows 8及以上版本 - 奇怪),而且在System.Json中也有相同的“JsonValue”,但它仍处于预览阶段,只有上帝知道它是否会被发布。当涉及到Json时,微软让我感到困惑。 - nawfal

45

除了需要引用System.Web.Extensions,并不需要任何第三方库的本地解决方案是使用JavaScriptSerializer。虽然这不是什么新东西,但自3.5以来一直存在,而且非常不为人知。

using System.Web.Script.Serialization;

..

JavaScriptSerializer serializer = new JavaScriptSerializer();
objectString = serializer.Serialize(new MyObject());

并返回

MyObject o = serializer.Deserialize<MyObject>(objectString)

2
这很不错,但它需要Web组件,所以遗憾的是它不能在.NET 4.0客户端框架中工作,这是Windows XP的最后一个.NET版本。完整安装.NET是可能的,但许多人只使用客户端框架。相比之下,System.Runtime.Serialization.Json.DataContractJsonSerializer甚至在客户端框架中也得到了支持。 - Al Kepp
3
Windows XP在桌面市场份额排名第二,这一点很重要。 - DonkeyMaster
当我使用JavaScriptSerializer反序列化我的对象时,它可以工作,但是它将我的日期反序列化错误了。它应该是4/19/2018 12:00AM,但是反序列化为4/18/2018 08:00PM。NewtonSoft.Json.JsonConvert按预期进行了反序列化。 - Rich

43

System.Text.Json

.NET Core 3.0自带 System.Text.Json,这意味着你可以在不使用第三方库的情况下对JSON进行反序列化/序列化。

序列化/反序列化

将你的类序列化为JSON字符串:

var json = JsonSerializer.Serialize(model);

将JSON反序列化为强类型类:

var model = JsonSerializer.Deserialize<Model>(json);

解析 (.NET 6)

.NET 6引入了System.Text.Json.Nodes 命名空间,该命名空间使用新类JsonObjectJsonArrayJsonValueJsonNode ,以类似于 Newtonsoft.Json 的方式实现 DOM 解析、导航和操作。

// JsonObject parse DOM
var jsonObject = JsonNode.Parse(jsonString).AsObject();
// read data from DOM
string name = jsonObject["Name"].ToString();
DateTime date = (DateTime)jsonObject["Date"];
var people = jsonObject["People"].Deserialize<List<Person>>();

类似的方法适用于 JsonArray。这个答案提供了关于 JsonObject 更多的细节说明。


需要注意的一点是,在使用自己的代码时,System.Text.Json 不会自动处理 camelCase JSON 属性(但在使用 MVC/WebAPI 请求和模型绑定器时会处理)。

要解决此问题,您需要将 JsonSerializerOptions 作为参数传递。

JsonSerializerOptions options = new JsonSerializerOptions
{        
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,  // set camelCase       
    WriteIndented = true                                // write pretty json
};

// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);

System.Text.Json也可作为一个Nu-get包在.Net Framework和.Net Standard中使用 System.Text.Json

Edit

在.NET 6中,JsonNode.Parse()提供解析“未知”json的功能。


3
如果你没有一个类怎么办?如果你只有模糊的了解 json 数据将包含什么?或者键是否存在都不确定呢? - Cherona
5
请使用JsonDocument.Parse进行解析。 - haldo
3
在 .NET 6 中,JsonNode.Parse() 提供了解析“未知” JSON 的功能。 - haldo

21

现在System.Json可用...

安装NuGet https://www.nuget.org/packages/System.Json

PM> Install-Package System.Json -Version 4.5.0

示例:

// PM>Install-Package System.Json -Version 4.5.0

using System;
using System.Json;

namespace NetCoreTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Note that JSON keys are case sensitive, a is not same as A.

            // JSON Sample
            string jsonString = "{\"a\": 1,\"b\": \"string value\",\"c\":[{\"Value\": 1}, {\"Value\": 2,\"SubObject\":[{\"SubValue\":3}]}]}";

            // You can use the following line in a beautifier/JSON formatted for better view
            // {"a": 1,"b": "string value","c":[{"Value": 1}, {"Value": 2,"SubObject":[{"SubValue":3}]}]}

            /* Formatted jsonString for viewing purposes:
            {
               "a":1,
               "b":"string value",
               "c":[
                  {
                     "Value":1
                  },
                  {
                     "Value":2,
                     "SubObject":[
                        {
                           "SubValue":3
                        }
                     ]
                  }
               ]
            }
            */

            // Verify your JSON if you get any errors here
            JsonValue json = JsonValue.Parse(jsonString);

            // int test
            if (json.ContainsKey("a"))
            {
                int a = json["a"]; // type already set to int
                Console.WriteLine("json[\"a\"]" + " = " + a);
            }

            // string test
            if (json.ContainsKey("b"))
            {
                string b = json["b"];  // type already set to string
                Console.WriteLine("json[\"b\"]" + " = " + b);
            }

            // object array test
            if (json.ContainsKey("c") && json["c"].JsonType == JsonType.Array)
            {
                // foreach loop test
                foreach (JsonValue j in json["c"])
                {
                    Console.WriteLine("j[\"Value\"]" + " = " + j["Value"].ToString());
                }

                // multi level key test
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][0]["Value"].ToString());
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][1]["Value"].ToString());
                Console.WriteLine("json[\"c\"][1][\"SubObject\"][0][\"SubValue\"]" + " = " + json["c"][1]["SubObject"][0]["SubValue"].ToString());
            }

            Console.WriteLine();
            Console.Write("Press any key to exit.");
            Console.ReadKey();
        }
    }
}

1
尝试寻找如何正确使用现代System.Json的示例,让我来到了这里,在经历了无数关于Json.NET/Newtonsoft.Json/"Newtson.Json"和早期版本的System.Json已被弃用的结果之后。感谢您提供这个信息。 - monkey0506
1
这对我帮助很大。非常感谢你。 - MAK
1
对于.NET Core,从终端执行以下命令:"dotnet add package System.Json --version 4.5.0" - Shaybc

21

1
这样做更好,因为它与.NET 3.5兼容。 - Mahmoud Fayez
它也比JavaScriptSerializer快得多。 - David
FYI,这在 .Net Core 中不再受支持。 - Liam

14
使用此工具根据您的JSON生成一个类: http://json2csharp.com/ 然后使用该类来反序列化您的JSON。示例:
public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}


string json = @"{
  'Email': 'james@example.com',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);
// james@example.com

References: https://forums.asp.net/t/1992996.aspx?Nested+Json+Deserialization+to+C+object+and+using+that+object https://www.newtonsoft.com/json/help/html/DeserializeObject.htm


11

请尝试下面的代码:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
JArray array = new JArray();
using (var twitpicResponse = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(twitpicResponse.GetResponseStream()))
{
    JavaScriptSerializer js = new JavaScriptSerializer();
    var objText = reader.ReadToEnd();

    JObject joResponse = JObject.Parse(objText);
    JObject result = (JObject)joResponse["result"];
    array = (JArray)result["Detail"];
    string statu = array[0]["dlrStat"].ToString();
}

这行代码有什么作用吗?JavaScriptSerializer js = new JavaScriptSerializer(); 谢谢。 - Chris Catignani

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