JsonSerializer.Deserialize 失败
JsonSerializer.Deserialize fails
考虑代码...
using System;
using System.Text.Json;
public class Program
{
public static void Main()
{
int id = 9;
string str = "{\"id\": " + id + "}";
var u = JsonSerializer.Deserialize<User>(str);
Console.WriteLine($"User ID: {u.Id}, Correct: {id == u.Id}"); // always 0/init/default value
}
}
public class User {
public int Id { get; set; }
}
为什么数据没有被正确反序列化到 User
对象中?我还通过 DotNetFiddle 验证了该行为,以防这是我系统的本地问题。没有抛出异常。
我的实际实现是从我 return Created("user", newUser)
之后的 [ApiController]
的 [HttpPost]
操作中读取的。它在我的 MVC/Razor 项目中通过 _httpClient.PostAsync
调用。当 Created
返回到 PostAsync
调用时,我验证了值是正确的,但无论如何,从响应主体解析的值仅包含默认值(实际 ID 是 Guid
).
我最初认为这可能是一个与 UTF8 相关的问题,因为这是 StringContent
我 post 到 ApiController
的编码。 UTF8 反序列化被引用 here,但我无法从 HttpContent
的 IO.Stream 到 ReadOnlySpan
或 Utf8JsonReader
.
我在搜索时发现 this project,这让我觉得它应该按我的预期工作。
感谢mr5 who suggested it was a casing issue via chat。
将字符串更改为使用 TitleCase ("Id") 解决了问题。
我正在提交工单,其中一个 possibly related issues comments lead me to another issue, which lead to the documentation, which has a solution
var options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
使用选项,解决问题...
string str = "{\"id\": " + id + "}";
var options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
var u = JsonSerializer.Deserialize<User>(str, options);
将此全部保留以防对其他人有帮助。
您的问题是 System.Text.Json
默认区分大小写,因此 "id": 9
(全部小写)未映射到 Id
属性。来自 docs:
Case-insensitive property matching
By default, deserialization looks for case-sensitive property name matches between JSON and the target object properties. To change that behavior, set JsonSerializerOptions.PropertyNameCaseInsensitive
to true
:
Note: The web default is case-insensitive.
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
};
var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options);
所以你也需要这样做:
var u = JsonSerializer.Deserialize<User>(str, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
演示 fiddle #1 here.
(如果差异完全是由于驼峰式大小写而不是更普遍的大小写差异,您可以将序列化器配置为使用驼峰式大小写,如 by t.j. 所示。)
您可以在 ASP.NET Core 3.0 中配置启动选项,如 :
所示
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
或者您可以将 [JsonPropertyName("id")]
应用于您的模型:
public class User {
[JsonPropertyName("id")]
public int Id { get; set; }
}
演示 fiddle #2 here.
在 ConfigureServices
在 Startup.cs
services.AddControllers()
.AddJsonOptions(o => {
o.JsonSerializerOptions.PropertyNamingPolicy=JsonNamingPolicy.CamelCase;
o.PropertyNameCasInsensitive=true
});
您还可以阅读此 Microsoft 文档 JSON Serialization,对于配置,您可以使用以下内容:
JsonSerializerOptions _jsonOptions = new(JsonSerializerDefaults.Web);
var serialized = JsonSerializer.Serialize(data, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<TEntity>(serialized , _jsonOptions);
JsonSerializerDefaults.Web 它是预定义的枚举设置,如“camelCase 值”、“不区分大小写的 属性 名称”等,检查此 JsonSerializerDefaults.?
, 如果你想自定义你会再次检查文档 here
考虑代码...
using System;
using System.Text.Json;
public class Program
{
public static void Main()
{
int id = 9;
string str = "{\"id\": " + id + "}";
var u = JsonSerializer.Deserialize<User>(str);
Console.WriteLine($"User ID: {u.Id}, Correct: {id == u.Id}"); // always 0/init/default value
}
}
public class User {
public int Id { get; set; }
}
为什么数据没有被正确反序列化到 User
对象中?我还通过 DotNetFiddle 验证了该行为,以防这是我系统的本地问题。没有抛出异常。
我的实际实现是从我 return Created("user", newUser)
之后的 [ApiController]
的 [HttpPost]
操作中读取的。它在我的 MVC/Razor 项目中通过 _httpClient.PostAsync
调用。当 Created
返回到 PostAsync
调用时,我验证了值是正确的,但无论如何,从响应主体解析的值仅包含默认值(实际 ID 是 Guid
).
我最初认为这可能是一个与 UTF8 相关的问题,因为这是 StringContent
我 post 到 ApiController
的编码。 UTF8 反序列化被引用 here,但我无法从 HttpContent
的 IO.Stream 到 ReadOnlySpan
或 Utf8JsonReader
.
我在搜索时发现 this project,这让我觉得它应该按我的预期工作。
感谢mr5 who suggested it was a casing issue via chat。
将字符串更改为使用 TitleCase ("Id") 解决了问题。
我正在提交工单,其中一个 possibly related issues comments lead me to another issue, which lead to the documentation, which has a solution
var options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
使用选项,解决问题...
string str = "{\"id\": " + id + "}";
var options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
var u = JsonSerializer.Deserialize<User>(str, options);
将此全部保留以防对其他人有帮助。
您的问题是 System.Text.Json
默认区分大小写,因此 "id": 9
(全部小写)未映射到 Id
属性。来自 docs:
Case-insensitive property matching
By default, deserialization looks for case-sensitive property name matches between JSON and the target object properties. To change that behavior, set
JsonSerializerOptions.PropertyNameCaseInsensitive
totrue
:Note: The web default is case-insensitive.
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, }; var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, options);
所以你也需要这样做:
var u = JsonSerializer.Deserialize<User>(str, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
演示 fiddle #1 here.
(如果差异完全是由于驼峰式大小写而不是更普遍的大小写差异,您可以将序列化器配置为使用驼峰式大小写,如
您可以在 ASP.NET Core 3.0 中配置启动选项,如
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
或者您可以将 [JsonPropertyName("id")]
应用于您的模型:
public class User {
[JsonPropertyName("id")]
public int Id { get; set; }
}
演示 fiddle #2 here.
在 ConfigureServices
在 Startup.cs
services.AddControllers()
.AddJsonOptions(o => {
o.JsonSerializerOptions.PropertyNamingPolicy=JsonNamingPolicy.CamelCase;
o.PropertyNameCasInsensitive=true
});
您还可以阅读此 Microsoft 文档 JSON Serialization,对于配置,您可以使用以下内容:
JsonSerializerOptions _jsonOptions = new(JsonSerializerDefaults.Web);
var serialized = JsonSerializer.Serialize(data, _jsonOptions);
var deserialized = JsonSerializer.Deserialize<TEntity>(serialized , _jsonOptions);
JsonSerializerDefaults.Web 它是预定义的枚举设置,如“camelCase 值”、“不区分大小写的 属性 名称”等,检查此 JsonSerializerDefaults.? , 如果你想自定义你会再次检查文档 here