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 到 ReadOnlySpanUtf8JsonReader.

我在搜索时发现 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.

ConfigureServicesStartup.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