-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
In .NET 10.0.100-rc.1.25451.107
, I am trying to manually create a JsonPatchDocument
(rather than receive one created by a client). I can do that quite easily, but when I serialize it using System.Text.Json, "from":null
properties will be shown for operations that should not have a "from"
property:
- "add"
- "remove"
- "replace"
- "test"
For instance, taking an example from JSON Patch RFC 6902, if I try to create the following patch:
[{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }]
Using the following code:
JsonPatchDocument patchDocument = new ();
patchDocument.Add("/a/b/c", new [] { "foo", "bar" });
var json = JsonSerializer.Serialize(patchDocument);
I will get
[{"value":["foo","bar"],"path":"/a/b/c","op":"add","from":null}]
That "from":null
definitely should not be present as can be seen from the RFC. What's more, the serialized JSON Patch could be considered to be invalid, since null
is a malformed JSON Pointer value.
In addition, when I checked the docs and reference source for OperationBase.from
, I see it is not marked as nullable:
[JsonPropertyName(nameof(from))]
public string from { get; set; }
Since from
will in fact be null for many operations, this is not strictly correct.
Checking a bit further, it seems you copied the code for the new OperationBase
almost verbatim from the Json.NET-based Microsoft.AspNetCore.JsonPatch.Operations.OperationBase
. That code has a method ShouldSerializefrom()
when prevents inappropriate "from"
values from being serialized. Because over in Microsoft.AspNetCore.JsonPatch.SystemTextJson.Operations.OperationBase
there is also a public function ShouldSerializeFrom()
. However, System.Text.Json doesn't support the ShouldSerializeXXX()
pattern out of the box, which seems to be causing the issue I am reporting.
I have not checked whether there is a similar problem serializing JsonPatchDocument<TModel>
.
Expected Behavior
"from"
values should only be emitted for Move and Copy operations, and so"from":null
should never be emitted when aJsonPatchDocument
is serialized.OperationBase.from
probably should be marked as nullable.- Consider removing the useless
OperationBase.ShouldSerializeFrom()
.
E.g. perhaps the following would be sufficient:
[JsonPropertyName(nameof(from)), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? from { get; set; }
Alternatively, if you want to preserve the logic that only writes "from"
for Move and Copy operations (rather than just skipping it when null) you might need to write a manual converter since System.Text.Json does not have builtin support for the ShouldSerializeXXX()
pattern.
Steps To Reproduce
//dotnet new console
//dotnet add package Microsoft.AspNetCore.JsonPatch.SystemTextJson --prerelease
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
JsonPatchDocument patchDocument = new ();
patchDocument.Add("/a/b/c", new [] { "foo", "bar" });
var json = JsonSerializer.Serialize(patchDocument);
Console.WriteLine(json); // Prints [{"value":["foo","bar"],"path":"/a/b/c","op":"add","from":null}]
var expectedJson = """[{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }]"""; // Taken from https://www.rfc-editor.org/rfc/rfc6902#section-4.1
Debug.Assert(JsonNode.DeepEquals(JsonNode.Parse(expectedJson), JsonNode.Parse(json))); // Fails due to "from":null
Exceptions (if any)
None (incorrect JSON is generated without an exception thrown.)
.NET Version
10.0.100-rc.1.25451.107
Anything else?
dotnet --info
:
.NET SDK:
Version: 10.0.100-rc.1.25451.107
Commit: 2db1f5ee2b
Workload version: 10.0.100-manifests.0e2d47c4
MSBuild version: 17.15.0-preview-25451-107+2db1f5ee2
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19045
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\10.0.100-rc.1.25451.107\