Newtonsoft.Json基本用法

发布时间 2023-11-06 15:33:42作者: 赵书记

序列化和反序列化JSON

JsonConvert

对于想要与 JSON 字符串相互转换的简单场景, JsonConvert 上的SerializeObject ()和 DeserializeObject () 方法在 JsonSerializer 上提供了易于使用的包装器。

下面代码使用序列化与反序列化:

 1 class Product
 2 {
 3     [JsonIgnore]
 4     public string Name { get; set; }
 5     public DateTime ExpiryDate { get; set; }
 6     public int Price { get; set; }
 7     public string[] Sizes { get; set; }
 8 
 9 }
10 Product product = new()
11 {
12     Name = "Davis",
13     ExpiryDate = DateTime.Now,
14     Price = 158,
15     Sizes = new[] {"small","medium","large"}
16 };
17 string output = JsonConvert.SerializeObject(product);  
18 Product product1 = JsonConvert.DeserializeObject<Product>(output);

 

注意:因为Product类中的Name特性为[JsonIgnore]所以忽略了此属性

 

output结果如图:

 

product1结果如图:

JsonSerializer

为了更好地控制对象的序列化方式,可以直接使用JsonSerializer 。JsonSerializer 能够通过JsonTextReader 和JsonTextWriter直接读取 JSON 文本并将其写入流。还可以使用其他类型的 JsonWriter,例如 JTokenReader / JTokenWriter将对象与 LINQ 对象相互转换为 JSON 对象,或者 BsonReader / BsonWriter将对象与 BSON 相互转换。

使用JsonSeriallizer将Json序列化为流,代码如下:

 1 Product product = new Product();
 2 product.ExpiryDate = new DateTime(2008, 12, 28);
 3 
 4 JsonSerializer serializer = new JsonSerializer();
 5 serializer.Converters.Add(new JavaScriptDateTimeConverter());
 6 serializer.NullValueHandling = NullValueHandling.Ignore;
 7 
 8 using (StreamWriter sw = new StreamWriter(@"c:\json.txt"))
 9 using (JsonWriter writer = new JsonTextWriter(sw))
10 {
11     serializer.Serialize(writer, product);
12     // {"ExpiryDate":new Date(1230375600000),"Price":0}
13 }

 

序列化指南

在较高级别上,Json.NET 序列化器会将原始 .NET 值转换为原始 JSON 值,将 .NET 数组和集合转换为 JSON 数组,并将其他所有内容转换为 JSON 对象。

Json.NET 在反序列化值时如果遇到不正确的 JSON,将会抛出错误。例如,如果序列化程序遇到带有值数组的 JSON 属性,并且匹配的 .NET 属性的类型不是集合,则将引发错误,反之亦然。

Complex Types
.NET JSON
IList, IEnumerable, IList<T>, Array Array (properties on the collection will not be serialized)
IDictionary, IDictionary<TKey, TValue> Object (dictionary name/values only, properties on the dictionary will not be serialized)
Object (more detail below) Object

 

 

 

 

 

Primitive Types
String String

Byte SByte Uint16

int16 UInt16 Int32

UInt64 Int64

Integer
Float Double Decimal Float
Enum Integer (can be the enum value name with StringEnumConverter)
DataTime String (Serializing Dates in JSON)
Byte[] String (base 64 encoded)
Type String (type name)
Guid String
TypeConverter (convertible to String) String

 

 

 

 

 

 

 

 

 

 

 

 

序列化Attributes

Attributes可用于控制 Json.NET 如何序列化和反序列化 .NET 对象。

  • JsonObjectAttribute - 放置在类上以控制如何将它们序列化为 JSON 对象。

  • JsonArrayAttribute - 放置在集合上以控制如何将它们序列化为 JSON 数组。

  • JsonDictionaryAttribute - 放置在字典上以控制如何将它们序列化为 JSON 对象。

  • JsonPropertyAttribute - 放置在字段和属性上,以控制如何将它们序列化为 JSON 对象中的属性。

  • JsonConverterAttribute - 放置在类或字段和属性上,以指定序列化期间应使用哪个 JsonConverter。

  • JsonExtensionDataAttribute - 放置在集合字段或属性上,用于将没有匹配类成员的属性反序列化到指定的集合中,并在序列化期间写入值。

  • JsonConstructorAttribute - 放置在构造函数上以指定应在反序列化期间使用它来创建类。

Json.NET Serialization Attributes

此属性上的 MemberSerialization 标志指定成员序列化是否是选择加入(成员必须具有要序列化的 JsonProperty 或 DataMember 属性)、选择退出(默认情况下会序列化所有内容,但可以使用 JsonIgnoreAttribute(Json.NET 的默认值)来忽略行为)或字段(所有公共和私有字段都被序列化,并且属性被忽略)。

JsonArrayAttribute和 JsonDictionaryAttribute用于指定类是否序列化为该集合类型

JsonPropertyAttribute 有多种用途:

  • 默认情况下,JSON 属性将与 .NET 属性具有相同的名称。此属性允许自定义名称。

  • JsonPropertyAttribute 指示当成员序列化设置为选择加入时应序列化属性。

  • 它包括序列化和反序列化中的非公共属性。

  • 它可用于自定义属性值的类型名称、引用、null 和默认值处理。

  • 可用于自定义序列化属性名称的NamingStrategy 。

  • 它可用于自定义属性的集合项 JsonConverter、类型名称处理和引用处理。

从序列化中排除字段或属性。NonSerializedAttribute可以替代JsonIgnoreAttribute

JsonConverterAttribute指定使用哪个 JsonConverter转换对象。该属性可以放置在类或成员上。当放置在类上时,属性指定的 JsonConverter 将是序列化该类的默认方式。当属性位于字段或属性上时,指定的 JsonConverter 将始终用于序列化该值。使用 JsonConverter 的优先级是成员属性,然后是类属性,最后是传递给 JsonSerializer 的任何转换器。

实例代码如下:

 1 public enum UserStatus
 2 {
 3     NotConfirmed,
 4     Active,
 5     Deleted
 6 }
 7 
 8 public class User
 9 {
10     public string UserName { get; set; }
11 
12     [JsonConverter(typeof(StringEnumConverter))]
13     public UserStatus Status { get; set; }
14 }

 

JsonExtensionDataAttribute指示 JsonSerializer将类型上没有匹配字段或属性的属性反序列化到指定集合中在序列化期间,此集合中的值将写回实例的 JSON 对象。

示例代码如下:

 1 public class DirectoryAccount
 2 {
 3     // normal deserialization
 4     public string DisplayName { get; set; }
 5 
 6     // these properties are set in OnDeserialized
 7     public string UserName { get; set; }
 8     public string Domain { get; set; }
 9 
10     [JsonExtensionData]
11     private IDictionary<string, JToken> _additionalData;
12 
13     [OnDeserialized]
14     private void OnDeserialized(StreamingContext context)
15     {
16         // SAMAccountName is not deserialized to any property
17         // and so it is added to the extension data dictionary
18         string samAccountName = (string)_additionalData["SAMAccountName"];
19 
20         Domain = samAccountName.Split('\\')[0];
21         UserName = samAccountName.Split('\\')[1];
22     }
23 
24     public DirectoryAccount()
25     {
26         _additionalData = new Dictionary<string, JToken>();
27     }
28 }
29 
30 string json = @"{
31   'DisplayName': 'John Smith',
32   'SAMAccountName': 'contoso\\johns'
33 }";
34 
35 DirectoryAccount account = JsonConvert.DeserializeObject<DirectoryAccount>(json);
36 
37 Console.WriteLine(account.DisplayName);
38 // John Smith
39 
40 Console.WriteLine(account.Domain);
41 // contoso
42 
43 Console.WriteLine(account.UserName);
44 // johns

 

JsonConstructorAttribute指示 JsonSerializer在反序列化类时使用特定的构造函数它可用于使用参数化构造函数而不是默认构造函数来创建类,或者在有多个构造函数时选择要使用的特定参数化构造函数。

代码如下:

 1 public class User
 2 {
 3     public string UserName { get; private set; }
 4     public bool Enabled { get; private set; }
 5 
 6     public User()
 7     {
 8     }
 9 
10     [JsonConstructor]
11     public User(string userName, bool enabled)
12     {
13         UserName = userName;
14         Enabled = enabled;
15     }
16 }
17 string json = @"{
18   ""UserName"": ""domain\\username"",
19   ""Enabled"": true
20 }";
21 
22 User user = JsonConvert.DeserializeObject<User>(json);
23 
24 Console.WriteLine(user.UserName);
25 // domain\username

 

 

上面大概介绍了一些Json.net的Attribute,及基本概念,下面将列举一些常用示例

序列化对象

 1 public class Account
 2 {
 3     public string Email { get; set; }
 4     public bool Active { get; set; }
 5     public DateTime CreatedDate { get; set; }
 6     public IList<string> Roles { get; set; }
 7 }
 8 
 9 Account account = new Account
10 {
11     Email = "james@example.com",
12     Active = true,
13     CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc),
14     Roles = new List<string>
15     {
16         "User",
17         "Admin"
18     }
19 };
20 
21 string json = JsonConvert.SerializeObject(account, Formatting.Indented);
22 // {
23 //   "Email": "james@example.com",
24 //   "Active": true,
25 //   "CreatedDate": "2013-01-20T00:00:00Z",
26 //   "Roles": [
27 //     "User",
28 //     "Admin"
29 //   ]
30 // }
31 
32 Console.WriteLine(json);

 

序列化集合

 1 List<string> videogames = new List<string>
 2 {
 3     "Starcraft",
 4     "Halo",
 5     "Legend of Zelda"
 6 };
 7 
 8 string json = JsonConvert.SerializeObject(videogames);
 9 
10 Console.WriteLine(json);
11 // ["Starcraft","Halo","Legend of Zelda"]

序列化字典

 1 Dictionary<string, int> points = new Dictionary<string, int>
 2 {
 3     { "James", 9001 },
 4     { "Jo", 3474 },
 5     { "Jess", 11926 }
 6 };
 7 
 8 string json = JsonConvert.SerializeObject(points, Formatting.Indented);
 9 
10 Console.WriteLine(json);
11 // {
12 //   "James": 9001,
13 //   "Jo": 3474,
14 //   "Jess": 11926
15 // }

 

将Json序列化到文件

 1 public class Movie
 2 {
 3     public string Name { get; set; }
 4     public int Year { get; set; }
 5 }
 6 
 7 Movie movie = new Movie
 8 {
 9     Name = "Bad Boys",
10     Year = 1995
11 };
12 
13 // serialize JSON to a string and then write string to a file
14 File.WriteAllText(@"c:\movie.json", JsonConvert.SerializeObject(movie)); //先序列化成字符串,再到文件
15 
16 // serialize JSON directly to a file
17 using (StreamWriter file = File.CreateText(@"c:\movie.json")) //将序列化直接到文件
18 {
19     JsonSerializer serializer = new JsonSerializer();
20     serializer.Serialize(file, movie);
21 }

 

使用JsonConverters进行序列化

 1 List<StringComparison> stringComparisons = new List<StringComparison>
 2 {
 3     StringComparison.CurrentCulture,
 4     StringComparison.Ordinal
 5 };
 6 
 7 string jsonWithoutConverter = JsonConvert.SerializeObject(stringComparisons);
 8 
 9 Console.WriteLine(jsonWithoutConverter);
10 // [0,4]
11 
12 string jsonWithConverter = JsonConvert.SerializeObject(stringComparisons, new StringEnumConverter());
13 
14 Console.WriteLine(jsonWithConverter);
15 // ["CurrentCulture","Ordinal"]
16 
17 List<StringComparison> newStringComparsions = JsonConvert.DeserializeObject<List<StringComparison>>(
18     jsonWithConverter,
19     new StringEnumConverter());
20 
21 Console.WriteLine(string.Join(", ", newStringComparsions.Select(c => c.ToString()).ToArray()));
22 // CurrentCulture, Ordinal

 

序列化DataSet

 1 DataSet dataSet = new DataSet("dataSet");
 2 dataSet.Namespace = "NetFrameWork";
 3 DataTable table = new DataTable();
 4 DataColumn idColumn = new DataColumn("id", typeof(int));
 5 idColumn.AutoIncrement = true;
 6 
 7 DataColumn itemColumn = new DataColumn("item");
 8 table.Columns.Add(idColumn);
 9 table.Columns.Add(itemColumn);
10 dataSet.Tables.Add(table);
11 
12 for (int i = 0; i < 2; i++)
13 {
14     DataRow newRow = table.NewRow();
15     newRow["item"] = "item " + i;
16     table.Rows.Add(newRow);
17 }
18 
19 dataSet.AcceptChanges();
20 
21 string json = JsonConvert.SerializeObject(dataSet, Formatting.Indented);
22 
23 Console.WriteLine(json);
24 // {
25 //   "Table1": [
26 //     {
27 //       "id": 0,
28 //       "item": "item 0"
29 //     },
30 //     {
31 //       "id": 1,
32 //       "item": "item 1"
33 //     }
34 //   ]
35 // }

 

反序列化对象

 1 public class Account
 2 {
 3     public string Email { get; set; }
 4     public bool Active { get; set; }
 5     public DateTime CreatedDate { get; set; }
 6     public IList<string> Roles { get; set; }
 7 }
 8 
 9 
10 string json = @"{
11   'Email': 'james@example.com',
12   'Active': true,
13   'CreatedDate': '2013-01-20T00:00:00Z',
14   'Roles': [
15     'User',
16     'Admin'
17   ]
18 }";
19 
20 Account account = JsonConvert.DeserializeObject<Account>(json);
21 
22 Console.WriteLine(account.Email);
23 // james@example.com

 反序列化集合

1 string json = @"['Starcraft','Halo','Legend of Zelda']";
2 
3 List<string> videogames = JsonConvert.DeserializeObject<List<string>>(json);
4 
5 Console.WriteLine(string.Join(", ", videogames.ToArray()));
6 // Starcraft, Halo, Legend of Zelda

反序列化字典

 1 string json = @"{
 2   'href': '/account/login.aspx',
 3   'target': '_blank'
 4 }";
 5 
 6 Dictionary<string, string> htmlAttributes = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
 7 
 8 Console.WriteLine(htmlAttributes["href"]);
 9 // /account/login.aspx
10 
11 Console.WriteLine(htmlAttributes["target"]);
12 // _blank

 

反序列化匿名类型

var definition = new { Name = "" };

string json1 = @"{'Name':'James'}";
var customer1 = JsonConvert.DeserializeAnonymousType(json1, definition);

Console.WriteLine(customer1.Name);
// James

string json2 = @"{'Name':'Mike'}";
var customer2 = JsonConvert.DeserializeAnonymousType(json2, definition);

Console.WriteLine(customer2.Name);
// Mike

 

反序列化DataSet

 1 string json = @"{
 2   'Table1': [
 3     {
 4       'id': 0,
 5       'item': 'item 0'
 6     },
 7     {
 8       'id': 1,
 9       'item': 'item 1'
10     }
11   ]
12 }";
13 
14 DataSet dataSet = JsonConvert.DeserializeObject<DataSet>(json);
15 
16 DataTable dataTable = dataSet.Tables["Table1"];
17 
18 Console.WriteLine(dataTable.Rows.Count);
19 // 2
20 
21 foreach (DataRow row in dataTable.Rows)
22 {
23     Console.WriteLine(row["id"] + " - " + row["item"]);
24 }
25 // 0 - item 0
26 // 1 - item 1

题外知识,如何把DataGridView转换为DataTable?代码如下

 1 DataTable dt = new DataTable();
 2 foreach(DataGridViewColumn col in dgv.Columns)
 3 {
 4    dt.Columns.Add(col.Name);    
 5 }
 6 
 7 foreach(DataGridViewRow row in dgv.Rows)
 8 {
 9     DataRow dRow = dt.NewRow();
10     foreach(DataGridViewCell cell in row.Cells)
11     {
12         dRow[cell.ColumnIndex] = cell.Value;
13     }
14     dt.Rows.Add(dRow);
15 }

 

从文件反序列化

 1 public class Movie
 2 {
 3     public string Name { get; set; }
 4     public int Year { get; set; }
 5 }
 6 
 7 // read file into a string and deserialize JSON to a type
 8 Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(@"c:\movie.json"));
 9 
10 // deserialize JSON directly from a file
11 using (StreamReader file = File.OpenText(@"c:\movie.json"))
12 {
13     JsonSerializer serializer = new JsonSerializer();
14     Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
15 }

反序列当前相对路径中的Json文件,代码如下:

 1 Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(Environment.CurrentDirectory + "\\tsconfig1.json")); 

 

填充对象

使用Json中的值填充现有对象实例

 1 public class Account
 2 {
 3     public string Email { get; set; }
 4     public bool Active { get; set; }
 5     public DateTime CreatedDate { get; set; }
 6     public List<string> Roles { get; set; }
 7 }
 8 
 9 Account account = new Account
10 {
11     Email = "james@example.com",
12     Active = true,
13     CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc),
14     Roles = new List<string>
15     {
16         "User",
17         "Admin"
18     }
19 };
20 
21 string json = @"{
22   'Active': false,
23   'Roles': [
24     'Expired'
25   ]
26 }";
27 
28 JsonConvert.PopulateObject(json, account);
29 
30 Console.WriteLine(account.Email);
31 // james@example.com
32 
33 Console.WriteLine(account.Active);
34 // false
35 
36 Console.WriteLine(string.Join(", ", account.Roles.ToArray()));
37 // User, Admin, Expired

 

构造函数反序列化处理设置

此示例使用ConstructorHandling设置通过其非公共构造函数成功反序列化该类。

 1 public class Website
 2 {
 3     public string Url { get; set; }
 4 
 5     private Website()
 6     {
 7     }
 8 
 9     public Website(Website website)
10     {
11         if (website == null)
12         {
13             throw new ArgumentNullException(nameof(website));
14         }
15 
16         Url = website.Url;
17     }
18 }
19 
20 
21 string json = @"{'Url':'http://www.google.com'}";
22 
23 try
24 {
25     JsonConvert.DeserializeObject<Website>(json);
26 }
27 catch (Exception ex)
28 {
29     Console.WriteLine(ex.Message);
30     // Value cannot be null.
31     // Parameter name: website
32 }
33 
34 Website website = JsonConvert.DeserializeObject<Website>(json, new JsonSerializerSettings
35 {
36     ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
37 });
38 
39 Console.WriteLine(website.Url);
40 // http://www.google.com

 

对象创建处理设置

此示例通过将ObjectCreationHandling 设置为 Replace 来反序列化 JSON,以便集合值不会重复。

 1 public class UserViewModel
 2 {
 3     public string Name { get; set; }
 4     public IList<string> Offices { get; private set; }
 5 
 6     public UserViewModel()
 7     {
 8         Offices = new List<string>
 9         {
10             "Auckland",
11             "Wellington",
12             "Christchurch"
13         };
14     }
15 }
16 
17 string json = @"{
18   'Name': 'James',
19   'Offices': [
20     'Auckland',
21     'Wellington',
22     'Christchurch'
23   ]
24 }";
25 
26 UserViewModel model1 = JsonConvert.DeserializeObject<UserViewModel>(json);
27 
28 foreach (string office in model1.Offices)
29 {
30     Console.WriteLine(office);
31 }
32 // Auckland
33 // Wellington
34 // Christchurch
35 // Auckland
36 // Wellington
37 // Christchurch
38 
39 UserViewModel model2 = JsonConvert.DeserializeObject<UserViewModel>(json, new JsonSerializerSettings
40 {
41     ObjectCreationHandling = ObjectCreationHandling.Replace
42 });
43 
44 foreach (string office in model2.Offices)
45 {
46     Console.WriteLine(office);
47 }
48 // Auckland
49 // Wellington
50 // Christchurch

 

默认值处理设置

此示例使用DefaultValueHandling设置来不序列化具有默认值的属性。

 1 public class Person
 2 {
 3     public string Name { get; set; }
 4     public int Age { get; set; }
 5     public Person Partner { get; set; }
 6     public decimal? Salary { get; set; }
 7 }
 8 
 9 Person person = new Person();
10 
11 string jsonIncludeDefaultValues = JsonConvert.SerializeObject(person, Formatting.Indented);
12 
13 Console.WriteLine(jsonIncludeDefaultValues);
14 // {
15 //   "Name": null,
16 //   "Age": 0,
17 //   "Partner": null,
18 //   "Salary": null
19 // }
20 
21 string jsonIgnoreDefaultValues = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
22 {
23     DefaultValueHandling = DefaultValueHandling.Ignore
24 });
25 
26 Console.WriteLine(jsonIgnoreDefaultValues);
27 // {}

 

缺少成员处理设置

此示例尝试在MissingMemberHandling 设置为错误且 JSON 属性与成员不匹配的情况下反序列化 JSON,从而导致异常。

 1 public class Account
 2 {
 3     public string FullName { get; set; }
 4     public bool Deleted { get; set; }
 5 }
 6 
 7 string json = @"{
 8   'FullName': 'Dan Deleted',
 9   'Deleted': true,
10   'DeletedDate': '2013-01-20T00:00:00'
11 }";
12 
13 try
14 {
15     JsonConvert.DeserializeObject<Account>(json, new JsonSerializerSettings
16     {
17         MissingMemberHandling = MissingMemberHandling.Error
18     });
19 }
20 catch (JsonSerializationException ex)
21 {
22     Console.WriteLine(ex.Message);
23     // Could not find member 'DeletedDate' on object of type 'Account'. Path 'DeletedDate', line 4, position 23.
24 }

 

空值处理设置

此示例将对象序列化为 JSON,并将NullValueHandling 设置为“忽略”,以便具有默认值的属性不会包含在 JSON 结果中。

 1 public class Person
 2 {
 3     public string Name { get; set; }
 4     public int Age { get; set; }
 5     public Person Partner { get; set; }
 6     public decimal? Salary { get; set; }
 7 }
 8 
 9 
10 Person person = new Person
11 {
12     Name = "Nigal Newborn",
13     Age = 1
14 };
15 
16 string jsonIncludeNullValues = JsonConvert.SerializeObject(person, Formatting.Indented);
17 
18 Console.WriteLine(jsonIncludeNullValues);
19 // {
20 //   "Name": "Nigal Newborn",
21 //   "Age": 1,
22 //   "Partner": null,
23 //   "Salary": null
24 // }
25 
26 string jsonIgnoreNullValues = JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings
27 {
28     NullValueHandling = NullValueHandling.Ignore
29 });
30 
31 Console.WriteLine(jsonIgnoreNullValues);
32 // {
33 //   "Name": "Nigal Newborn",
34 //   "Age": 1
35 // }