29
       {
          "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??
                }
            }
        }
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(). Commented Oct 9, 2019 at 11:00
  • yes, exactly my question how can I add new attribute after loading JsonDocument? I am unable to find any method in their documentation. Commented Oct 9, 2019 at 11:27
  • 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. Commented Nov 25, 2019 at 23:56
  • 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. Commented Jun 2, 2020 at 9:30
  • 1
    You cannot add property using System.Text.Json. Use Newtonsoft JObject to add properties to your Json Object. Refer this -> JObject Commented Jun 3, 2020 at 10:45

5 Answers 5

32

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";
Sign up to request clarification or add additional context in comments.

1 Comment

This is the preferred way now.
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.

2 Comments

"I'm pretty sure a much better solution should exist." exactly
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.
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.

Comments

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));
    }

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.