How to add property in existing json using System.Text.Json library?
Asked Answered
C

5

26
       {
          "TestData":{
              "Year__of__Account":"2019",
              "Tax___x0025_":"0.06",
              "Buildings__1":"1000",
              "Contents__1":"400",
              "Total_Insurable_Value":"100",
              "Buildings__Prem":"2560.8",
              "Contents__Prem":"1707.2",
              "YB__1":"1950",
              "No__Buildings":"55",
              "Location_Sprinklers_YN":"No",
              "test":"test"
           }
        }

In the above sample JSON I want to add a property called "Name" with Value "John" inside property "TestData". How can I achieve this using .net Core 3.0 System.Text.Json library.

I have tried using methods of Utf8JsonWriter but it is creating a new JSON object instead of appending it to the above existing JSON.

        using (MemoryStream memoryStream1 = new MemoryStream())
        {
            using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
            {
                using (JsonDocument jsonDocument = JsonDocument.Parse(json))
                {
                    utf8JsonWriter1.WriteStartObject();
                    utf8JsonWriter1.WritePropertyName("Name");
                    utf8JsonWriter1.WriteStringValue("John");
                    utf8JsonWriter1.WriteEndObject();

                    // how can I add above properties to JsonDocument object??
                }
            }
        }
Cesaro answered 9/10, 2019 at 10:51 Comment(5)
I haven't personally gotten around to installing VS2019/Core3 yet, so I haven't done this myself, but presumably you would load the document in with JsonDocument.Parse(), as you do, add the new attribute, and then write it out with JsonDocument.WriteTo().Ogive
yes, exactly my question how can I add new attribute after loading JsonDocument? I am unable to find any method in their documentation.Cesaro
JsonDocument is read-only. There is an open issue Writable Json DOM #39922 tracking this. Related but not duplicate: Modifying a JSON file using System.Text.Json.Laktasic
Were you able to resolve this issue? I am having issues with inserting property at specified location, so wondering if you could help with the following question. I can use both Newtonsoft or System.Text.Json.Baste
You cannot add property using System.Text.Json. Use Newtonsoft JObject to add properties to your Json Object. Refer this -> JObjectCesaro
R
26

Starting from .NET 6 you can use JsonNode. This is a modifiable, dictionary-backed API to complement the readonly JsonDocument.

For your example, the solution would be as follows:

var jsonNode = JsonNode.Parse(json);
jsonNode["TestData"]["Name"] = "John";
Ragen answered 17/5, 2022 at 13:59 Comment(1)
This is the preferred way now.Nahshu
S
12

Assuming there may be several properties and you want to add a name only to "TestData" property:

using (MemoryStream memoryStream1 = new MemoryStream())
{
    using (Utf8JsonWriter utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
    {
        using (JsonDocument jsonDocument = JsonDocument.Parse(json))
        {
            utf8JsonWriter1.WriteStartObject();

            foreach (var element in jsonDocument.RootElement.EnumerateObject())
            {
                if (element.Name == "TestData")
                {
                    utf8JsonWriter1.WritePropertyName(element.Name);

                    // Staring new object
                    utf8JsonWriter1.WriteStartObject();

                    // Adding "Name" property 
                    utf8JsonWriter1.WritePropertyName("Name");
                    utf8JsonWriter1.WriteStringValue("John");

                    // Copying existing values from "TestData" object
                    foreach (var testDataElement in element.Value.EnumerateObject())
                    {
                        testDataElement.WriteTo(utf8JsonWriter1);
                    }

                    utf8JsonWriter1.WriteEndObject();
                }
                else
                {
                    element.WriteTo(utf8JsonWriter1);
                }
            }

            utf8JsonWriter1.WriteEndObject();
        }
    }

    var resultJson = Encoding.UTF8.GetString(memoryStream1.ToArray());
}

Here for each property (except for "TestData" property) I write the whole value as is (by calling element.WriteTo(utf8JsonWriter1)), and for "TestData" property I start a new object, add "Name" property and then copy each of the "TestData" object's properties.

P.S. This works, but I'm pretty sure a much better solution should exist.

Segregate answered 22/10, 2019 at 18:53 Comment(2)
"I'm pretty sure a much better solution should exist." exactlyCorpuz
It is kind of a workaround since you are creating a new JSON object from an existing one. But maybe this is the only solution to my problem since there are no methods available in System.Text.Json library for JSON object manipulation.Cesaro
T
5

I've just created a NuGet package with some hopefully useful extension methods for JsonElement, which allow properties to be added and/or removed. It's based on using the Utf8JsonWriter to create a new mutated JsonElement based on the original, like the answer above.

GitHub repo | NuGet package

var jsonString = "{ \"Name\": \"Andrew\", \"EmailAddress\": \"[email protected]\" }";
var jElement = JsonDocument.Parse(jsonString).RootElement;

jElement = jElement.AddProperty("Age", 38)
.AddProperty("Male", true)
.AddProperty("Female", false)
.AddNullProperty("Alien")
.AddProperty("Roles", new string[] { "admin", "user" })
.AddProperty("LastUpdated", DateTime.UtcNow)
.AddProperty("crazyNewObject", new
{
    Name = "Hobbies",
    Value = "bass guitar and writing c# code"
});

Hopefully someone will find them useful, but if they don't do quite what you need, please enhance and submit a pull request.

Tatary answered 28/2, 2020 at 23:23 Comment(0)
C
4

Here is a possible answer

static void Main(string[] args)
    {
        var jsonString = @"
        {
            ""TestData"":{
                ""Year__of__Account"":""2019"",
                ""Tax___x0025_"":""0.06"",
                ""Buildings__1"":""1000"",
                ""Contents__1"":""400"",
                ""Total_Insurable_Value"":""100"",
                ""Buildings__Prem"":""2560.8"",
                ""Contents__Prem"":""1707.2"",
                ""YB__1"":""1950"",
                ""No__Buildings"":""55"",
                ""Location_Sprinklers_YN"":""No"",
                ""test"":""test""
            }
        }
        ";

        var jsonDoc = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);

        var testDataDict = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonDoc["TestData"].ToString());

        testDataDict.Add("Name", "John");

        //replace the test data with the modified test data
        jsonDoc["TestData"] = testDataDict;

        Console.WriteLine(JsonSerializer.Serialize(jsonDoc));
    }
Cristen answered 24/10, 2019 at 2:46 Comment(0)
F
0

Using JsonSerializer to deserialize into a nested dictionary is also possible:

static void Main(string[] args)
{
    string testJson = @"
    {
    ""TestData"":{
        ""Year__of__Account"":""2019"",
        ""Tax___x0025_"":""0.06"",
        ""Buildings__1"":""1000"",
        ""Contents__1"":""400"",
        ""Total_Insurable_Value"":""100"",
        ""Buildings__Prem"":""2560.8"",
        ""Contents__Prem"":""1707.2"",
        ""YB__1"":""1950"",
        ""No__Buildings"":""55"",
        ""Location_Sprinklers_YN"":""No"",
        ""test"":""test""
        }
    }";

    using (var memoryStream1 = new MemoryStream())
    {
        using (var utf8JsonWriter1 = new Utf8JsonWriter(memoryStream1))
        {
            //For each level in json tree an additional dictionary must be added
            var jsonDict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, object>>>(testJson);
            jsonDict["TestData"].Add("Name", "John");
            JsonSerializer.Serialize<object>(utf8JsonWriter1, jsonDict);
        }

        string testString = Encoding.UTF8.GetString(memoryStream1.ToArray());
    }
}

But note that the new property is always added at the end of the TestData block.

Fourteen answered 4/5, 2020 at 20:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.