- 
                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":nullshould never be emitted when aJsonPatchDocumentis serialized.OperationBase.fromprobably 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\