【问题标题】:Does the new `System.Text.Json` have a required property attribute?新的 `System.Text.Json` 是否具有必需的属性属性?
【发布时间】:2020-02-14 23:57:11
【问题描述】:

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

我正在寻找的是这个:

public class Videogame
{
    [JsonProperty(Required = Required.Always)]
    public string Name { get; set; }
}

我只是遗漏了什么,还是 Microsoft 库中不存在这种级别的验证?

【问题讨论】:

标签: c# .net-core json.net system.text.json


【解决方案1】:

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

JsonConverterAttribute
JsonExtensionDataAttribute
JsonIgnoreAttribute
JsonPropertyNameAttribute

更新:.NET 5.0 中的集合是

JsonConstructorAttribute
JsonConverterAttribute
JsonExtensionDataAttribute
JsonIgnoreAttribute
JsonIncludeAttribute
JsonNumberHandlingAttribute
JsonPropertyNameAttribute

不幸的是,即使在How to write custom converters for JSON serialization (marshalling) in .NET 中显示的带有HandleNull => true 的自定义转换器也无法工作,因为如果不存在该属性,则不会调用 Read 和 Write 方法(在 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);

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

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

【讨论】:

    【解决方案2】:

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

    您会发现对 JsonRequiredAttribute 的支持。

    public class Videogame
    {
        [JsonRequired(RequirementPolicy.Always)]
        public string Name { get; set; }
    }
    

    通过在命名空间 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);
    

    【讨论】:

    • 太糟糕了 BGE2 永远不会出来 :(
    【解决方案3】:

    截至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; }
    }
    

    注意如果 JSON 中缺少构造函数参数,该库不会引发错误。它只使用类型的默认值(所以0 代表int)。如果您想处理这种情况,最好使用可为空的值类型。

    此外,构造函数参数的类型必须与您的字段/属性完全匹配,因此不幸的是,不能从 int? 转到 int。我发现分析属性 [NotNull] 和/或 [DisallowNulls] 减少了不便。

    【讨论】:

    • NotNull 究竟如何提供帮助?它添加了静态代码分析检查,对吗?
    • @ryanwebjackson 之类的。如果您为空处理启用了警告,[NotNull] 会告诉编译器该成员不需要空检查。 [DisallowNulls] 确保在构造函数完成之前它有一个值。见documentation
    • 有趣。我没有在 Microsoft 文档中找到此信息。谢谢你的解释。
    【解决方案4】:

    我正在使用System.ComponentModel.DataAnnotations 中提供的通用[Required] 属性。我已经将它与Newtonsoft.JsonSystem.Text.Json 一起使用。

    【讨论】:

    • 它有什么帮助?
    • 例如当你想在一个请求对象中注释某个属性是必需的,传递给一个API控制器。
    • 该属性可能会在特定框架(如 MVC)中用完堆栈,但不会由 System.Text.Json 的 JsonSerializer 强制执行。
    • 最初的问题可能更多是关于强制执行所需的属性(因为它是在 Newtonsoft.Json 而不是在 System.Text.Json 中完成的),而不仅仅是将它们标记为必需...
    猜你喜欢
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-05
    相关资源
    最近更新 更多