JsonSerializerOptions options = new JsonSerializerOptions
TypeInfoResolver = new DefaultJsonTypeInfoResolver
Modifiers =
static typeInfo =>
if (typeInfo.Kind != JsonTypeInfoKind.Object)
return;
foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
if("UserName".Equals(propertyInfo.Name))
propertyInfo.IsRequired = true;
string json = """
{"Age":null,"IsCheck":true,"Birthday":"2000-12-20T01:01:01"}
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json, options);
默认情况下,JSON 中不允许使用注释和尾随逗号,
注释处理枚举:
public enum JsonCommentHandling : byte
// 摘要:
// Doesn't allow comments within the JSON input. Comments are treated as invalid
// JSON if found, and a System.Text.Json.JsonException is thrown. This is the default
// value.
Disallow = 0,
// 摘要:
// Allows comments within the JSON input and ignores them. The System.Text.Json.Utf8JsonReader
// behaves as if no comments are present.
Skip = 1,
// 摘要:
// Allows comments within the JSON input and treats them as valid tokens. While
// reading, the caller can access the comment values.
Allow = 2
举个例子:
class UserDTO
public string UserName { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
public DateTime? Birthday { get; set; }
public bool? IsCheck { get; set; }
public Dictionary<String, object> Ext { get; set; }
public Gender? UserGender { get; set; }
JsonSerializerOptions options = new JsonSerializerOptions
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true // true-允许最后一个对象后面加逗号
string json = """
/* 注释风格 */
"Age": 123, // 年龄
"Score": 1.23, // 得分
"IsCheck": true,
"Birthday": "2000-12-20T01:01:01", // 最后加个逗号
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json, options);
这个很实用的一个特性,上游系统提供的数字可能是带引号,默认是严格区分类型,反序列化会失败的
枚举JsonNumberHandling
针对数字的序列化、反序列化可以做特殊设置
public enum JsonNumberHandling
// 摘要:
// Numbers will only be read from System.Text.Json.JsonTokenType.Number tokens and
// will only be written as JSON numbers (without quotes).
Strict = 0,
// 摘要:
// Numbers can be read from System.Text.Json.JsonTokenType.String tokens. Does not
// prevent numbers from being read from System.Text.Json.JsonTokenType.Number token.
AllowReadingFromString = 1,
// 摘要:
// Numbers will be written as JSON strings (with quotes), not as JSON numbers.
WriteAsString = 2,
// 摘要:
// The "NaN", "Infinity", and "-Infinity" System.Text.Json.JsonTokenType.String
// tokens can be read as floating-point constants, and the System.Single and System.Double
// values for these constants will be written as their corresponding JSON string
// representations.
AllowNamedFloatingPointLiterals = 4
class UserDTO
public string UserName { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
public DateTime? Birthday { get; set; }
public bool? IsCheck { get; set; }
public Dictionary<String, object> Ext { get; set; }
public Gender? UserGender { get; set; }
JsonSerializerOptions options = new JsonSerializerOptions
NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString
string json = """
{"Age":"123","Score":"1.23","IsCheck":true,"Birthday":"2000-12-20T01:01:01"}
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json, options);
这是一个很重要的特性,如果JSON字符串提供了远超接收对象的字段,默认情况下会忽略掉这些多余的字段,但是现在可以进行参数设置做不通的处理
配置枚举:
public enum JsonUnmappedMemberHandling
// 默认设置,忽略多于的字段
Skip = 0,
// 字段对不上,直接抛异常
Disallow = 1
举个例子:
[JsonUnmappedMemberHandling(JsonUnmappedMemberHandling.Disallow)]
class UserDTO
public string UserName { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
public DateTime? Birthday { get; set; }
public bool? IsCheck { get; set; }
public Dictionary<String, object> Ext { get; set; }
public Gender? UserGender { get; set; }
string json = """
"Abc": "xxx",
"Age": 123,
"Score": 1.23,
"IsCheck": true,
"Birthday": "2000-12-20T01:01:01"
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);
当JSON字符串字段多余接收对象的场景,
1、常规做法就是接收对象继续增加字段
2、偷懒做法通过JsonExtensionData
统一用一个Dictionary
接收所有未被映射的字段
举个例子:
未被映射的Abc
,List
,Map
全部会放到ExtensionData
字段中
class UserDTO
public string UserName { get; set; }
//[JsonRequired]
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
public DateTime? Birthday { get; set; }
public bool? IsCheck { get; set; }
public Dictionary<String, object> Ext { get; set; }
public Gender? UserGender { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement> ExtensionData { get; set; }
string json = """
"Age": 123,
"Score": 1.23,
"IsCheck": true,
"Birthday": "2000-12-20T01:01:01",
"Abc": "xxx",
"List": ["北京", "上海", "广州", "深圳"],
"Map": {
"A": 1,
"B": "张三"
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);
1、接收对象中每一个字段都需要考虑数据类型完全对接上,但是JsonElement
与JsonNode
是一个万能接收数据类型
2、唯一注意的是JsonElement
是值类型,保险期间使用可空类型
3、JsonNode
是可变对象,JsonElement
是不可变对象
举个例子:
class UserDTO
public JsonNode UserName { get; set; }
public JsonNode Age { get; set; }
public JsonNode Score { get; set; }
public JsonElement? Birthday { get; set; }
public JsonElement? IsCheck { get; set; }
public JsonElement? UserGender { get; set; }
[JsonExtensionData]
public Dictionary<string, JsonElement> ExtensionData { get; set; }
string json = """
"UserName": "张三",
"Age": null,
"Score": null,
"IsCheck": null,
"Birthday": null
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);
1、接收对象有设置值的场景,反序列化的时候默认是进行替换操作,现在可以通过参数控制
2、一般用于集合类型,如果是普通单值类型,有默认值,有设置成填充模式,反而可能会抛异常
JsonObjectCreationHandling
控制
// 按类设置
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class UserDTO1
public List<int> Score{ get; } = [1, 2, 3];
// 按类设置
class UserDTO2
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Score{ get; } = [1, 2, 3];
举个例子:
class UserDTO
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Score { get; set; } = [1, 2, 3];
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public Dictionary<string, int> Age { get; set; } = new Dictionary<string, int>
{ "one", 1 },
{ "two", 2 },
{ "three", 3 }
string json = """
"Score": [4, 5, 6],
"Age" : {"张三" : 10}
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json);
class UserDTO
public List<int> Score { get; set; }
public Dictionary<string, int> Age { get; set; }
JsonSerializerOptions options = new JsonSerializerOptions
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate
string json = """
"Score": [4, 5, 6],
"Age" : {"张三" : 10}
UserDTO user = JsonSerializer.Deserialize<UserDTO>(json, options);
JsonNode
创建的DOM
是可变的,可以通过 JsonNode
、JsonObject
、JsonArray
、JsonValue
和 JsonElement
进行操作
JsonDocument
生成只读 DOM
。 可以通过 JsonElement
进行操作
JsonNode
是一个抽象类,具体实现是JsonObject
public sealed class JsonObject : JsonNode, ICollection<KeyValuePair<string, JsonNode?>>, IEnumerable<KeyValuePair<string, JsonNode?>>, IEnumerable, IDictionary<string, JsonNode?>
public sealed class JsonArray : JsonNode, ICollection<JsonNode?>, IEnumerable<JsonNode?>, IEnumerable, IList<JsonNode?>
public abstract class JsonValue : JsonNode
举个例子,编辑JsonNode
JsonObject jo = new JsonObject();
jo.Add("Age",20);
jo.Add("Height", 123.45);
jo.Add("Name", "张三");
jo.Add("CityList", JsonValue.Create(new List<string>() { "北京", "上海", "广州", "深圳" }));
jo.Add("Ext", JsonValue.Create(new Dictionary<string, int>
{ "one", 1 },
{ "two", 2 },
{ "three", 3 }
jo["Age"] = 30;
Console.WriteLine(jo.ToString());
举个例子,遍历JsonNode:
string json = """
"Age": 20,
"Height": 185.6,
"ScoreList": [4, 5, 6],
"CityList": ["北京", "上海", "广州", "深圳"],
"ExtMap": {
"A": "hello",
"B": "world"
JsonNode node = JsonNode.Parse(json)!;
if (node is JsonObject)
PrintJsonObect((JsonObject)node);
else if (node is JsonArray)
PrintJsonObect((JsonArray)node);
private static void PrintJsonObect(JsonValue val)
Console.WriteLine($"valType: {val.GetValueKind()}, value: {val}");
private static void PrintJsonObect(JsonObject jo)
foreach (KeyValuePair<string, JsonNode> item in jo)
Console.WriteLine($"key: {item.Key}");
if (item.Value is JsonObject)
PrintJsonObect((JsonObject)item.Value);
else if (item.Value is JsonArray)
PrintJsonObect((JsonArray)item.Value);
else if (item.Value is JsonValue)
PrintJsonObect((JsonValue)item.Value);
private static void PrintJsonObect(JsonArray ja)
foreach (JsonNode node in ja)
if (node is JsonObject)
PrintJsonObect((JsonObject)node);
else if (node is JsonArray)
PrintJsonObect((JsonArray)node);
else if (node is JsonValue)
PrintJsonObect((JsonValue)node);
举个例子:
string json = """
"Age": 20,
"Height": 185.6,
"ScoreList": [4, 5, 6],
"CityList": ["北京", "上海", "广州", "深圳"],
"ExtMap": {
"A": "hello",
"B": "world"
using (JsonDocument document = JsonDocument.Parse(json))
ProcessJsonElement(document.RootElement);
private static void ProcessJsonElement(JsonElement element)
switch (element.ValueKind)
case JsonValueKind.Object:
foreach (var property in element.EnumerateObject())
Console.WriteLine($"key: {property.Name}, type: {property.Value.ValueKind}");
if (property.Value.ValueKind == JsonValueKind.Object || property.Value.ValueKind == JsonValueKind.Array)
ProcessJsonElement(property.Value);
Console.WriteLine($"value: {property.Value}");
break;
case JsonValueKind.Array:
foreach (var item in element.EnumerateArray())
ProcessJsonElement(item);
break;
default:
Console.WriteLine($"value: {element}");
break;
在序列化、反序列化中有很多个性化的设置都是通过这个类来配置的
常用可设置的一些配置:
public sealed class JsonSerializerOptions
public int MaxDepth { get; set; }
public bool PropertyNameCaseInsensitive { get; set; }
public bool IncludeFields { get; set; }
public bool IgnoreReadOnlyProperties { get; set; }
public bool IgnoreNullValues { get; set; }
public int DefaultBufferSize { get; set; }
public bool AllowTrailingCommas { get; set; }
public bool IgnoreReadOnlyFields { get; set; }
public bool WriteIndented { get; set; }
public Serialization.JsonNumberHandling NumberHandling { get; set; }
public Serialization.JsonObjectCreationHandling PreferredObjectCreationHandling { get; set; }
public JsonNamingPolicy? PropertyNamingPolicy { get; set; }
public JsonCommentHandling ReadCommentHandling { get; set; }
public Serialization.ReferenceHandler? ReferenceHandler { get; set; }
public IJsonTypeInfoResolver? TypeInfoResolver { get; set; }
public Serialization.JsonUnknownTypeHandling UnknownTypeHandling { get; set; }
public Serialization.JsonUnmappedMemberHandling UnmappedMemberHandling { get; set; }
public JavaScriptEncoder? Encoder { get; set; }
public JsonNamingPolicy? DictionaryKeyPolicy { get; set; }
public Serialization.JsonIgnoreCondition DefaultIgnoreCondition { get; set; }
序列化、反序列化最大层次,默认64,一般没事不用修改这个配置
class UserDTO
public string UserName { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
List<UserDTO> SubUserList { get; set; }
JsonSerializerOptions options = new JsonSerializerOptions
MaxDepth = 4
string json = """
"UserName": "张三",
"Age": 18,
"Score": 89.2,
"SubUserList ": [{
"UserName": "李四",
"Age": 20,
"Score": 90,
"SubUserList": [{
"UserName": "王五",
"Age": 21,
"Score": 99.2
UserDTO userDTO = JsonSerializer.Deserialize<UserDTO>(json, options);
大小写不敏感,默认false,大小写敏感(反序列化场景
)
C#
默认是大驼峰命名规则,大小写敏感,但是上游系统返回的数据千奇百怪,这个属性可能有一定用处
JsonSerializerOptions options = new JsonSerializerOptions
PropertyNameCaseInsensitive = true
string json = """
"userName": "张三",
"age": 18,
"score": 89.2
UserDTO userDTO = JsonSerializer.Deserialize<UserDTO>(json, options);
true-忽略只读属性(序列化场景
)
举个例子:
class UserDTO
public string UserName { private get; set; }
public Nullable<int> Age { get; set; }
public Nullable<decimal> Score { get; set; }
public UserDTO(string userName)
UserName = userName;
JsonSerializerOptions options = new JsonSerializerOptions
IgnoreReadOnlyProperties = true
UserDTO userDTO = new UserDTO("张三");
userDTO.Age = 20;
userDTO.Score = 60;
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO, options));
true-忽略null
值(序列化、反序列化场景
)
该属性标记删除,以后用DefaultIgnoreCondition
设置空值处理
举个例子:
JsonSerializerOptions options = new JsonSerializerOptions
IgnoreNullValues = true
string json = """
"UserName": null,
"Age": null,
"Score": 89.2
UserDTO userDTO = JsonSerializer.Deserialize<UserDTO>(json, options);
userDTO.Age = 20;
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO, options));
// 会把null值的属性也输出
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO));
true-对象末尾支持有逗号,针对不太标准的JSON字符串(反序列化场景
)
JsonSerializerOptions options = new JsonSerializerOptions
AllowTrailingCommas = true
string json = """
"UserName": null,
"Age": null,
"Score": 89.2,
UserDTO userDTO = JsonSerializer.Deserialize<UserDTO>(json, options);
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO, options));
true-忽略只读(readonly
)字段(序列化场景
)
默认情况序列化的时候会忽略所有field
,首先输出要包含field
,可以使用IncludeFields
或 IncludeFields
包含field
class UserDTO
public readonly string Field1 = "只读属性";
public string Field2 = "非只读属性";
public string UserName { get; set; }
JsonSerializerOptions options = new JsonSerializerOptions
IgnoreReadOnlyFields = true,
IncludeFields = true
UserDTO userDTO = new UserDTO();
userDTO.UserName = "张三";
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO, options));
true-格式化输出(序列化场景
)
举个例子:
JsonSerializerOptions options = new JsonSerializerOptions
WriteIndented = true
UserDTO userDTO = new UserDTO();
userDTO.UserName = "张三";
userDTO.Age = 20;
userDTO.Score = 60;
Console.WriteLine(JsonSerializer.Serialize<UserDTO>(userDTO, options));
数字处理特殊配置(序列化
、反序列化
场景)
public enum JsonNumberHandling
Strict = 0,
AllowReadingFromString = 1,
WriteAsString = 2,
AllowNamedFloatingPointLiterals = 4
配置 | 场景 | 说明 |
---|
Strict | 反序列化 | 严格模式 |
AllowReadingFromString | 反序列化 | 支持字符串模式: {“Score”: “89.2” } |
WriteAsString | 序列化 | 数字序列化结果包含引号: {“Score”: “89.2” } |
AllowNamedFloatingPointLiterals | 序列化、反序列化 | 浮点型针对NaN , Infinity ,-Infinity 特殊处理 |
举个例子:
JsonSerializerOptions options = new JsonSerializerOptions
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
UserDTO userDTO = new UserDTO();
userDTO.UserName = "张三";
userDTO.Age = 20;
userDTO.Score = double.NaN;
string json = JsonSerializer.Serialize<UserDTO>(userDTO, options);
Console.WriteLine(json );
JsonSerializer.Deserialize<UserDTO>(json, options);
一般情况反序列化都是替换操作,但是针对集合 类型可以有一些特殊的配置,可以设置填充模式(反序列化
场景)
public enum JsonObjectCreationHandling
//替换模式
Replace = 0,
// 填充模式:
Populate = 1
举个例子:
JsonSerializerOptions options = new JsonSerializerOptions
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate
C#
是采用大驼峰命名规则,但是其他语言可能五花八门的方式(序列化
、反序列化
场景)
也可以扩展抽象类JsonNamingPolicy
实现自定义命名规则
命名策略 | 说明 | 原始属性名称 | 经过转换的属性名称 |
---|
CamelCase | 第一个单词以小写字符开头。连续单词以大写字符开头 | TempCelsius | tempCelsius |
KebabCaseLower | 单词由连字符分隔,所有字符均为小写 | TempCelsius | temp-celsius |
KebabCaseUpper | 单词由连字符分隔,所有字符均为大写 | TempCelsius | TEMP-CELSIUS |
SnakeCaseLower | 单词用下划线分隔,所有字符均为小写 | TempCelsius | temp_celsius |
SnakeCaseUpper | 单词用下划线分隔,所有字符均为大写 | TempCelsius | TEMP_CELSIUS |
举个例子: