Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

904
Visualizações
.NET Core/System.Text.Json: Enumerate and add/replace json properties/values

In an earlier question of mine I asked how to populate an existing object using System.Text.Json.

One of the great answers showed a solution parsing the json string with JsonDocument and enumerate it with EnumerateObject.

Over time my json string evolved and does now also contain an array of objects, and when parsing that with the code from the linked answer it throws the following exception:

The requested operation requires an element of type 'Object', but the target element has type 'Array'.

I figured out that one can in one way or the other look for the JsonValueKind.Array, and do something like this

if (json.ValueKind.Equals(JsonValueKind.Array))
{
    foreach (var item in json.EnumerateArray())
    {
        foreach (var property in item.EnumerateObject())
        {
            await OverwriteProperty(???);
        }
    }
}

but I can't make that work.

How to do this, and as a generic solution?

I would like to get "Result 1", where array items gets added/updated, and "Result 2" (when passing a variable), where the whole array gets replaced.

For "Result 2" I assume one can detect if (JsonValueKind.Array)) in the OverwriteProperty method, and where/how to pass the "replaceArray" variable? ... while iterating the array or the objects?

Some sample data:

Json string initial

{
  "Title": "Startpage",
  "Links": [
    {
      "Id": 10,
      "Text": "Start",
      "Link": "/index"
    },
    {
      "Id": 11,
      "Text": "Info",
      "Link": "/info"
    }
  ]
}

Json string to add/update

{
  "Head": "Latest news",
  "Links": [
    {
      "Id": 11,
      "Text": "News",
      "Link": "/news"
    },
    {
      "Id": 21,
      "Text": "More News",
      "Link": "/morenews"
    }
  ]
}

Result 1

{
  "Title": "Startpage",
  "Head": "Latest news"
  "Links": [
    {
      "Id": 10,
      "Text": "Start",
      "Link": "/indexnews"
    },
    {
      "Id": 11,
      "Text": "News",
      "Link": "/news"
    },
    {
      "Id": 21,
      "Text": "More news",
      "Link": "/morenews"
    }
  ]
}

Result 2

{
  "Title": "Startpage",
  "Head": "Latest news"
  "Links": [
    {
      "Id": 11,
      "Text": "News",
      "Link": "/news"
    },
    {
      "Id": 21,
      "Text": "More News",
      "Link": "/morenews"
    }
  ]
}

Classes

public class Pages
{
    public string Title { get; set; }
    public string Head { get; set; }
    public List<Links> Links { get; set; }
}

public class Links
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Link { get; set; }
}

C# code:

public async Task PopulateObjectAsync(object target, string source, Type type, bool replaceArrays = false)
{
    using var json = JsonDocument.Parse(source).RootElement;

    if (json.ValueKind.Equals(JsonValueKind.Array))
    {
        foreach (var item in json.EnumerateArray())
        {
            foreach (var property in item.EnumerateObject())
            {
                await OverwriteProperty(???, replaceArray);  //use "replaceArray" here ?
            }
        }
    }
    else
    {
        foreach (var property in json.EnumerateObject())
        {
            await OverwriteProperty(target, property, type, replaceArray);  //use "replaceArray" here ?
        }
    }

    return;
}

public async Task OverwriteProperty(object target, JsonProperty updatedProperty, Type type, bool replaceArrays)
{
    var propertyInfo = type.GetProperty(updatedProperty.Name);

    if (propertyInfo == null)
    {
        return;
    }

    var propertyType = propertyInfo.PropertyType;
    object parsedValue;

    if (propertyType.IsValueType)
    {
        parsedValue = JsonSerializer.Deserialize(
            updatedProperty.Value.GetRawText(),
            propertyType);
    }
    else if (replaceArrays && "property is JsonValueKind.Array")  //pseudo code sample
    {
        // use same code here as in above "IsValueType" ?
    }
    else
    {
        parsedValue = propertyInfo.GetValue(target);

        await PopulateObjectAsync(
            parsedValue,
            updatedProperty.Value.GetRawText(),
            propertyType);
    }

    propertyInfo.SetValue(target, parsedValue);
}
over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Well, If you don't care how the arrays are written, I have a simple solution. Create a new JSON within 2 phases 1 loop for new properties and 1 loop for the updates:

    var sourceJson = @"
{
  ""Title"": ""Startpage"",
  ""Links"": [
    {
      ""Id"": 10,
      ""Text"": ""Start"",
      ""Link"": ""/index""
    },
    {
      ""Id"": 11,
      ""Text"": ""Info"",
      ""Link"": ""/info""
    }
  ]
}";
        var updateJson = @"
{
  ""Head"": ""Latest news"",
  ""Links"": [
    {
      ""Id"": 11,
      ""Text"": ""News"",
      ""Link"": ""/news""
    },
    {
      ""Id"": 21,
      ""Text"": ""More News"",
      ""Link"": ""/morenews""
    }
  ]
}
";
        using var source = JsonDocument.Parse(sourceJson);
        using var update = JsonDocument.Parse(updateJson);
        using var stream = new MemoryStream();
        using var writer = new Utf8JsonWriter(stream);
        writer.WriteStartObject();
        // write non existing properties
        foreach (var prop in update.RootElement.EnumerateObject().Where(prop => !source.RootElement.TryGetProperty(prop.Name, out _)))
        {
            prop.WriteTo(writer);
        }

        // make updates for existing
        foreach (var prop in source.RootElement.EnumerateObject())
        {
            if (update.RootElement.TryGetProperty(prop.Name, out var overwrite))
            {
                writer.WritePropertyName(prop.Name);
                overwrite.WriteTo(writer);
            }
            else
            {
                prop.WriteTo(writer);
            }
        }

        writer.WriteEndObject();
        writer.Flush();
        var resultJson = Encoding.UTF8.GetString(stream.ToArray());
        Console.WriteLine(resultJson);

Output :

{
   "Head":"Latest news",
   "Title":"Startpage",
   "Links":[
      {
         "Id":11,
         "Text":"News",
         "Link":"/news"
      },
      {
         "Id":21,
         "Text":"More News",
         "Link":"/morenews"
      }
   ]
}

Fiddle

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda