Reputation: 4969
I'm been trying to use replace values within a nested object using JSON Patch, however I feel like I'm not getting the notation correct. Any ideas what the path should be?
I've created the following code to prove it in LINQPad 6.
void Main()
{
var patchTest = new PatchTest();
patchTest.Create();
patchTest.ToString().Dump("Before Patch");
var patch = JsonConvert.DeserializeObject<JsonPatchDocument<Contact>>(
@"[
{
""op"": ""replace"",
""path"": ""/firstname"",
""value"": ""Benjamin""
},
{
""op"": ""replace"",
""path"": ""age"",
""value"": ""29""
},
{
""op"": ""replace"",
""path"": ""//Appointment//Name"",
""value"": ""fsdfdsf""
},
]");
patchTest.Patch(patch);
patchTest.ToString().Dump("After Patch");
}
public class PatchTest
{
public Contact Contact { get; set; }
public PatchTest() { }
public void Create()
{
Contact = new Contact
{
FirstName = "Walt",
LastName = "Banks",
Age = 20
};
}
public void Patch(JsonPatchDocument<Contact> patch)
{
patch.Replace(e => e.Appointment, Contact.Appointment);
patch.ApplyTo(Contact);
}
public override string ToString()
{
return $"{nameof(Contact)}: {Contact}";
}
}
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Appointment Appointment { get; set; }
public override string ToString()
{
return $"{nameof(FirstName)}: {FirstName}, {nameof(LastName)}: {LastName}, {nameof(Appointment)}: {Appointment}";
}
}
public class Appointment
{
public string Name { get; set; }
public override string ToString()
{
return $"{nameof(Name)}: {Name}";
}
}
However it fails to find Name
Upvotes: 4
Views: 7217
Reputation: 26075
You are trying to set value for Name
property on Appointment
which is not initialized. Update Contact
class to initialize the property when creating new instnce:
public class Contact
{
public Contact()
{
Appointment = new Appointment();
}
...
}
as a rule of thumb, you should try to initialize all similar properties to make sure similar issue doesn't happen for other classes.
Upvotes: 3
Reputation: 14655
The reason it can't find the appointment name is because you've not initialised Appointment
when creating your Contact
. Change Create
to:
public void Create()
{
Contact = new Contact
{
FirstName = "Walt",
LastName = "Banks",
Age = 20,
Appointment = new Appointment()
};
}
Running your example in a console app now produces this output:
Before Patch
Contact: FirstName: Walt, LastName: Banks, Age: 20, Appointment: Name:
After Patch
Contact: FirstName: Benjamin, LastName: Banks, Age: 29, Appointment: Name: fsdfdsf
I added Contact.Age
to its ToString()
override, as it was missing. Also, single /
and double //
both work in the path. I'm guessing you used the latter when trying to figure out what was wrong.
Now, as you've already defined the document in JSON, you don't need to define another replacement operation. Your Patch
method can be simplified to:
public void Patch(JsonPatchDocument<Contact> patch)
{
patch.ApplyTo(Contact);
}
and the output will be the same as before. The equivalent of doing all of this in code, without manually creating the JSON document, would be as follows:
public void Patch(Contact amendedContact)
{
var patch = new JsonPatchDocument<Contact>();
patch.Replace(e => e.FirstName, amendedContact.FirstName);
patch.Replace(e => e.Age, amendedContact.Age);
patch.Replace(e => e.Appointment.Name, amendedContact.Appointment.Name);
patch.ApplyTo(Contact);
}
and calling it like so:
var amendedContact = new Contact
{
FirstName = "Benjamin",
Age = 29,
Appointment = new Appointment
{
Name = "fsdfdsf"
}
};
patchTest.Patch(amendedContact);
This again produces your desired output. But you'll still have to make sure nested properties are initialised, otherwise you'll run into the original problem.
Upvotes: 4