在 ASP.NET Core 中实现“JSON Merge Patch”——最好的方法是区分 null 和未定义的属性

use*_*r44 7 c# rest api-design asp.net-core

我想创建和端点符合“JSON Merge Patch” https://tools.ietf.org/html/rfc7396

请不要将它与“JavaScript Object Notation (JSON) Patch”混淆 https://tools.ietf.org/html/rfc6902

但是,我在区分请求中的两种情况时遇到了一个小问题:

出现问题是因为在模型绑定后的两种情况下,电子邮件的值为 null。

你有什么建议吗?

r.p*_*osa 2

我带着同样的问题来到这个帖子。我的解决方案类似于“CodeFuller”解决方案,但更完整,因为它涵盖了 swagger 的 API 文档,并且因为使用更少的代码而更好。它还使用它System.text.json来代替Newtonsoft库。

  1. 通过利用现有Optional结构来定义模型(无需创建新OptionalValue类)

    {
        public string Surname { get; set; }
    
        [JsonConverter(typeof(OptionalConverter<string>))]
        public Optional<string> Email { get; set; } = default;
    }
    
    
    Run Code Online (Sandbox Code Playgroud)
  2. 告诉 Swagger(如果适用)将格式设置为字符串输入/类型,以获得更好的客户端体验:

    c.MapType<Optional<string>>(() => new OpenApiSchema { Type = "string" });

  3. 添加基于以下内容的自定义 JSON 转换器System.text.json

    public class OptionalConverter<T> : JsonConverter<Optional<T>>
        {
            // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to
            public override bool CanConvert(Type typeToConvert) =>
                typeToConvert == typeof(Optional<T>);
    
            public override Optional<T> Read(
                ref Utf8JsonReader reader,
                Type typeToConvert,
                JsonSerializerOptions options) =>
                new Optional<T>(JsonSerializer.Deserialize<T>(ref reader, options));
    
            public override void Write(
                Utf8JsonWriter writer,
                Optional<T> value,
                JsonSerializerOptions options) =>
                throw new NotImplementedException("OptionalValue is not suppose to be written");
        }
    
    
    Run Code Online (Sandbox Code Playgroud)
  4. 那是。现在你有 3 个状态:

    [HttpPatch]
    [Consumes("application/merge-patch+json")]
    public void Patch([FromBody]SomeModel data)
    {
        if (data.Email.HasValue)
        {
            //  Email presents in Json
            if (data.Email.Value == null)
            {
                //  Email should be removed
            }
            else
            {
                //  Email should be updated
            }
        }
        else
        {
            //  Email does not present in Json and should not be affected
        }
    }
    
    
    Run Code Online (Sandbox Code Playgroud)