新的`System.Text.Json` 是否具有必需的属性属性?

THB*_*BFT 17 c# json.net .net-core system.text.json

我已经梳理了MS 文档,但找不到与NewtonSoft JsonPropertyRequired等效的属性。

我要找的是这个:

public class Videogame
{
    [JsonProperty(Required = Required.Always)]
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我是否只是遗漏了某些东西,或者 Microsoft 库中不存在这种级别的验证?

Sim*_*ver 11

前置:

特别提到了这个问题Required.Always,这Newtonsoft.Json将需要该属性并不允许空值(例如"firstName": null不允许)。

System.Text.Json相当于[JsonRequired](参见这篇文章),因为它必须有一个值,并且不允许为 null。

官方迁移文档目前在其他相关的 Newtonsoft 功能上非常薄弱。例如,Newtonsoft.Json您有以下四个枚举选项Required(这是 JsonProperty 上使用的属性):

Default        The property is not required. The default state.
AllowNull      The property must be defined in JSON but can be a null value.
Always         The property must be defined in JSON and cannot be a null value.
DisallowNull   The property is not required but it cannot be a null value.
Run Code Online (Sandbox Code Playgroud)

需要注意的是,这不是[JsonRequired]属性(来自 Newtonsoft),这意味着“...始终序列化成员,并要求成员具有值。”。

我不会尝试为上述内容制作一个映射表,因为我几乎肯定会弄错 - 而且我实际上认为这是不可能的。

然而,还有另一个相关属性 [JsonIgnore(Condition = JsonIgnoreCondition.XXXX]) [attribute][3] inSystem.Text.Json` 会影响序列化,并且可能更有用。

如果为 null,则使用[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]不会将值输出到 JSON。所以这有点类似于Required.AllowNull(但你不会[JsonRequired]再使用,因为它实际上并不需要!)。

最重要的是,这两个库之间并不完全相似,您使用它的方式将极大地影响迁移的难易程度。仔细计划!


.NET 7(2022 年 11 月)现在有了自己的版本[JsonRequired],许多人在看到如下错误时都会第一次发现:

“JsonRequired”是“Newtonsoft.Json.JsonRequiredAttribute”和“System.Text.Json.Serialization.JsonRequiredAttribute”之间的不明确引用

这可能是由于文件中包含以下两个 using 语句造成的:

using System.Text.Json.Serialization;
using Newtonsoft.Json;
Run Code Online (Sandbox Code Playgroud)

最简单、最安全的快速解决方案(如果您想继续使用 Newtonsoft)是搜索和替换并进行以下两个替换:

[JsonRequired] => [Newtonsoft.Json.JsonRequired]
[JsonRequired( => [Newtonsoft.Json.JsonRequired(
Run Code Online (Sandbox Code Playgroud)

仅当您的所有代码当前均为 .NET 6(此属性的使用必须来自 Newtonsoft)时,才能保证此功能有效。如果您要组合 .NET 6 和 .NET 7 项目中的代码,请务必小心。这就是我计划做的事情,以避免将来我切换时出现混乱(实际上我不打算这么做)。

如果您能够做到这一点,有一篇关于完全迁移到的更一般性的文章System.Text.Json


Kyl*_*lan 10

5.0开始,您可以使用构造函数来实现这一点。任何异常都会在反序列化期间出现。

public class Videogame
{
    public Videogame(string name, int? year)
    {
        this.Name = name ?? throw new ArgumentNullException(nameof(name));
        this.Year = year ?? throw new ArgumentNullException(nameof(year));
    }

    public string Name { get; }

    [NotNull]
    public int? Year { get; }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果 JSON 中缺少构造函数参数,该库不会抛出错误。它仅使用类型的默认值(因此0对于int)。如果您想处理这种情况,最好使用可空值类型。

此外,构造函数参数的类型必须与您的字段/属性完全匹配,因此不幸的是,不能从int?to进行int。我发现 System.Diagnostics.CodeAnalysis 命名空间中的分析属性[NotNull]和/或[DisallowNull]可以减轻这方面的不便。


tym*_*tam 9

.NET Core 3.0 不同。唯一支持的是:

JsonConverterAttribute
JsonExtensionDataAttribute
JsonIgnoreAttribute
JsonPropertyNameAttribute
Run Code Online (Sandbox Code Playgroud)

更新:在.NET 5.0 中,集合是

JsonConstructorAttribute
JsonConverterAttribute
JsonExtensionDataAttribute
JsonIgnoreAttribute
JsonIncludeAttribute
JsonNumberHandlingAttribute
JsonPropertyNameAttribute
Run Code Online (Sandbox Code Playgroud)

不幸的是,即使HandleNull => true如何为 .NET 中的 JSON 序列化(编组)编写自定义转换器中显示的自定义转换器也无法工作,因为如果不存在读取和写入方法中的属性不被调用(在 5.0 中测试,并且在3.0)

public class Radiokiller
{
    [JsonConverter(typeof(MyCustomNotNullConverter))] 
    public string Name { get; set; }  
}

public class MyCustomNotNullConverter : JsonConverter<string>
{
    public override bool HandleNull => true;

    public override string Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) =>
        reader.GetString() ?? throw new Exception("Value required.");

    public override void Write(
        Utf8JsonWriter writer,
        string value,
        JsonSerializerOptions options) =>
        writer.WriteStringValue(value);

}
Run Code Online (Sandbox Code Playgroud)
var json = "{}";
var o = JsonSerializer.Deserialize<Radiokiller>(json); // no exception :(

json = "{  \"Name\" : null}";
o = JsonSerializer.Deserialize<Radiokiller>(json); // throws
Run Code Online (Sandbox Code Playgroud)


Mic*_*iti 6

请试试我作为 System.Text.Json 扩展编写的这个库,以提供缺少的功能:https : //github.com/dahomey-technologies/Dahomey.Json

您将找到对 JsonRequiredAttribute 的支持。

public class Videogame
{
    [JsonRequired(RequirementPolicy.Always)]
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

通过调用命名空间 Dahomey.Json 中定义的扩展方法 SetupExtensions 的 JsonSerializerOptions 来设置 json 扩展。然后使用常规 Sytem.Text.Json API 反序列化您的类。

JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions();

const string json = @"{""Name"":""BGE2""}";
Videogame obj = JsonSerializer.Deserialize<Videogame>(json, options);
Run Code Online (Sandbox Code Playgroud)