如何为 System.Text.Json.JsonSerializer 全局设置默认选项?

Posted

技术标签:

【中文标题】如何为 System.Text.Json.JsonSerializer 全局设置默认选项?【英文标题】:How to globally set default options for System.Text.Json.JsonSerializer? 【发布时间】:2020-02-08 09:42:31 【问题描述】:

而不是这个:

JsonSerializerOptions options = new JsonSerializerOptions

    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
;
var so = JsonSerializer.Deserialize<SomeObject>(someJsonString, options);

我想做这样的事情:

// This property is a pleasant fiction
JsonSerializer.DefaultSettings = new JsonSerializerOptions

    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
;

// This uses my options
var soA = JsonSerializer.Deserialize<SomeObject>(someJsonString); 

// And somewhere else in the same codebase...
// This also uses my options
var soB = JsonSerializer.Deserialize<SomeOtherObject>(someOtherJsonString); 

希望在我们最常见的情况下不必传递JsonSerializerOptions 的实例,并为异常而不是规则覆盖。

如this q & a 所示,这是 Json.Net 的一个有用功能。我在the documentation 中查看了System.Text.Json 以及this GitHub repo 中的.NET Core。还有this one。

在 .NET Core 3 中似乎没有管理 JSON 序列化默认值的类比。还是我忽略了它?


更新 [2020-07-18]: 请参阅 this answer 了解 nuget package 以及支持默认设置的便捷方法。

更新 [2019 年 12 月 23 日]: 部分由于 community input 这个问题在 .NET 5.0 中是 added to the roadmap。

更新 [2019-10-10]: 如果有兴趣看到为 System.Text.Json.JsonSerializer 实施此行为,请前往致Chris Yungmann指出的the open GitHub issue并称重。

【问题讨论】:

There doesn't seem to be an analog for managing JSON serialization defaults in Core-3 -- 您是在谈论进出 API 的请求吗?还是对其他资源的请求和响应? @ps2goat 我不确定我是否理解您的问题。这里的问题是(反)序列化 JSON 字符串。它们可以来自任意数量的来源。 我之所以问,是因为在启动过程中有一些特殊的地方用于输入和输出格式化程序(例如,用于模型绑定) 啊,明白了。从这个意义上说,我认为我们的案例将属于“其他资源”。 @ps2goat 【参考方案1】:

您可以创建扩展方法。 Here's an example

我使用单独的方法而不是必须构建特殊设置,以便所有设置都在一个位置并且易于重复使用。

public static class DeserializeExtensions

    private static JsonSerializerOptions defaultSerializerSettings = new JsonSerializerOptions();

    // set this up how you need to!
    private static JsonSerializerOptions featureXSerializerSettings = new JsonSerializerOptions();


    public static T Deserialize<T>(this string json)
           
        return JsonSerializer.Deserialize<T>(json, defaultSerializerSettings);
    

    public static T DeserializeCustom<T>(this string json, JsonSerializerOptions settings)
    
        return JsonSerializer.Deserialize<T>(json, settings);
    

    public static T DeserializeFeatureX<T>(this string json)
    
        return JsonSerializer.Deserialize<T>(json, featureXSerializerSettings);
    

然后您将其作为字符串的方法调用,无论是文字还是变量。

    Car result = @"""Wheels"": 4, ""Doors"": 2".DeserializeFeatureX<Car>();

【讨论】:

【参考方案2】:

不,JsonSerializerOptions 不会公开default options。如果您使用的是特定的 Web 框架,则可能有一种方法可以通过它指定(反)序列化设置。否则,我建议您创建自己的便捷方法。

另见this open issue。

【讨论】:

【参考方案3】:

默认选项未在 .NET Core 3.1 的 JsonSerializer 中公开。但是,截至 2019 年 12 月,对于 5.0,这一直是 added to the road map。

.NET 5.0 的发布日期为 expected2020 年 11 月。但不能保证此特定问题会在任何特定时间得到解决。除了等待之外,这些答案还提供了一些解决方法:

https://***.com/a/58331912/1011722 https://***.com/a/58959198/1011722

此外,受@ps2goat 的回答启发,我打包了我的便利扩展方法,并将它们放在nuget.org 和github 上:

https://www.nuget.org/packages/Fetchgoods.Text.Json.Extensions/

【讨论】:

【参考方案4】:

这似乎对我有用,在 StartUp.ConfigureServices 中:

services.AddControllers().AddJsonOptions(options =>
    
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        options.JsonSerializerOptions.PropertyNamingPolicy=JsonNamingPolicy.CamelCase;
    );

【讨论】:

它确实有效。但是,它特定于配置控制器。 @TrevorReid 好点,如果你例如,这是一个问题。使用 Refit 从您的 asp.net 核心进行 API 调用 --> 然后 Refit 将忽略这些设置。【参考方案5】:

GitHub用户andre-ss6提出了一个workaround,如下:

((JsonSerializerOptions)typeof(JsonSerializerOptions)
    .GetField("s_defaultOptions", 
        System.Reflection.BindingFlags.Static |
        System.Reflection.BindingFlags.NonPublic).GetValue(null))
    .PropertyNameCaseInsensitive = true;

【讨论】:

这很好用,但很脆弱。我将使用它(我正在注册自定义类型转换器,不更改 PropertyNameCaseInsensitive,但前提是相同的)并祈祷它一直有效,直到 2020 年 11 月的预期发布,官方支持设置默认选项。 工作正常!谢谢【参考方案6】:

(如果你曾经改用 Json.NET)

我更喜欢并建议使用明确的设置并将设置传递给所有调用,但您可以使用 DefaultSettings 设置默认值。

JsonConvert.DefaultSettings = () => MySuperJsonSerializerSettings;

然后

var json = JsonConvert.SerializeObject(o1);
var o2 = JsonConvert.DeserializeObject(x);

【讨论】:

我猜你被否决了,因为问题是指 System.Text.Json 而不是 Newtonsofts (更好)包。在我的情况下,我没有选择“切换”到 Json.Net,因为在这个 Blazor Web 组装项目中该选项已被我拿走了。它远非伟大,它就是这样 “好多了”是一个观点问题——Newtonsoft.JSON 在配置和支持怪异(甚至无效的 json)方面肯定是“更好”的。但是,System.Text.Json 在性能(内存和 CPU)方面更好。

以上是关于如何为 System.Text.Json.JsonSerializer 全局设置默认选项?的主要内容,如果未能解决你的问题,请参考以下文章

如何为下拉菜单制作 CSS 边框?

如何为 CAShapeLayer 路径和填充颜色设置动画

iPhone - 如何为图像着色?

如何为 RecyclerView 设置 onItemClickListener? [复制]

WCF - 如何为 NTLM 身份验证配置 netTcpBinding?

如何为 UIToolbar 上的按钮添加滚动?