-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Closed
Labels
✔️ Resolution: AnsweredResolved because the question asked by the original author has been answered.Resolved because the question asked by the original author has been answered.Status: Resolvedarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templates
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
If a property is annotated with the [System.Text.Json.Serialization.JsonExtensionData] attribute, I expect the JsonPatchDocument.ApplyTo(...) method to map unknown paths to the respective property.
Instead (actual behaviour), an Microsoft.AspNetCore.JsonPatch.Exceptions.JsonPatchException is raised.
Expected Behavior
Unmapped paths in a JsonPatchDocument should be mapped (transparently) to the JsonExtensionData property.
By "transparently" I mean, that the client sending the patch to the server doesn't need to be aware of the ExtensionData property.
Steps To Reproduce
#nullable enable
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.JsonPatch;
using Microsoft.AspNetCore.JsonPatch.Operations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests;
class MyClass
{
public int Foo { get; set; }
public string Bar { get; set; }
[System.Text.Json.Serialization.JsonExtensionData]
public IDictionary<string, object>? MyExtensionData { get; set; }
}
[TestClass]
public class JsonPatchDocumentTest
{
[TestMethod]
[DataRow(true, false, false)]
[DataRow(false, false, false)]
[DataRow(false, true, false)]
// the following operations with "useStringlyTypedPath=true fail
[DataRow(true, false, true)]
[DataRow(false, false, true)]
[DataRow(false, true, true)]
public void TestPatchingExtensionData(bool initialExtensionDataAreEmpty, bool overwriteExistingExtensionData, bool useStringlyTypedPath)
{
if (initialExtensionDataAreEmpty && overwriteExistingExtensionData)
{
throw new Exception("This makes no sense");
}
string myEntityAsJson;
if (initialExtensionDataAreEmpty)
{
myEntityAsJson = """
{
"Foo": 17,
"Bar": "asd"
}
""";
}
else
{
myEntityAsJson = """
{
"Foo": 17,
"Bar": "asd",
"abc": "def"
}
""";
}
var myEntity = System.Text.Json.JsonSerializer.Deserialize<MyClass>(myEntityAsJson);
Assert.AreEqual(expected: initialExtensionDataAreEmpty, actual: myEntity.MyExtensionData is null);
var myPatch = new JsonPatchDocument<MyClass>();
myPatch.Add(x => x.Foo, 42);
myPatch.Add(x => x.Bar, "fgh");
string modifiedKey = overwriteExistingExtensionData ? "abc" : "uvw";
if (!useStringlyTypedPath)
{
// this code path works, but my client isn't aware of the extension data property nor its name
if (initialExtensionDataAreEmpty)
{
myPatch.Add(x => x.MyExtensionData, new Dictionary<string, object> { { modifiedKey, "xyz" } });
}
else
{
myPatch.Add(x => x.MyExtensionData[modifiedKey], "xyz");
}
}
else
{
// this is the behaviour of my client, which doesn't know about the extension data
myPatch.Operations.Add(new Operation<MyClass> { path = "/" + modifiedKey, op = "add", value = "xyz" });
}
myPatch.ApplyTo(myEntity);
// this throws a Microsoft.AspNetCore.JsonPatch.Exceptions.JsonPatchException:
// "The target location specified by path segment 'abc' was not found."
// "The target location specified by path segment 'uvw' was not found."
// Instead of the exception, I'd like to automatically map the path "/xyz" (or "/abc" respectively) to MyExtensionData
Assert.AreEqual(expected: 42, actual: myEntity.Foo);
Assert.AreEqual(expected: "fgh", actual: myEntity.Bar);
Assert.IsNotNull(myEntity.MyExtensionData);
Assert.IsTrue(myEntity.MyExtensionData.ContainsKey(modifiedKey));
Assert.AreEqual(expected: "xyz", actual: myEntity.MyExtensionData[modifiedKey]);
if (!overwriteExistingExtensionData && !initialExtensionDataAreEmpty)
{
Assert.IsTrue(myEntity.MyExtensionData.ContainsKey("abc"));
Assert.AreEqual(expected: "def", actual: myEntity.MyExtensionData["abc"].ToString());
}
}
}Exceptions (if any)
No response
.NET Version
8
Anything else?
No response
Metadata
Metadata
Assignees
Labels
✔️ Resolution: AnsweredResolved because the question asked by the original author has been answered.Resolved because the question asked by the original author has been answered.Status: Resolvedarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templates