Dans une question précédente, j'ai demandé comment faire pour alimenter un objet existant using System.Text.Json.
Une des grandes réponses a montré une solution en analysant la chaîne json avec JsonDocument
et l'énumérer avec EnumerateObject
.
Au fil du temps, ma chaîne json a évolué et contient maintenant un tableau d'objets, et lorsqu'elle est analysée avec le code de la réponse liée, elle lance l'exception suivante :
The requested operation requires an element of type 'Object', but the target element has type 'Array'.
J'ai compris que l'on peut, d'une manière ou d'une autre, rechercher les JsonValueKind.Array
et de faire quelque chose comme ceci
if (json.ValueKind.Equals(JsonValueKind.Array))
{
foreach (var item in json.EnumerateArray())
{
foreach (var property in item.EnumerateObject())
{
await OverwriteProperty(???);
}
}
}
mais je n'arrive pas à le faire fonctionner.
Comment procéder et quelle est la solution générique ?
Je souhaite obtenir "Résultat 1 où les éléments du tableau sont ajoutés/mise à jour, et "Résultat 2 (lors du passage d'une variable), où le tableau entier est remplacé.
Pour "Résultat 2 Je suppose que l'on peut détecter if (JsonValueKind.Array))
dans le OverwriteProperty
et où/comment passer la variable "replaceArray" ? ... pendant l'itération du tableau ou des objets ?
Quelques exemples de données :
Chaîne Json initiale
{
"Title": "Startpage",
"Links": [
{
"Id": 10,
"Text": "Start",
"Link": "/index"
},
{
"Id": 11,
"Text": "Info",
"Link": "/info"
},
]
}
Chaîne Json à ajouter/mettre à jour
{
"Head": "Latest news"
"Links": [
{
"Id": 11,
"Text": "News",
"Link": "/news"
},
{
"Id": 21,
"Text": "More News",
"Link": "/morenews"
}
]
}
Résultat 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"
}
]
}
Résultat 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; }
}
Code C# :
public async Task PopulateObjectAsync(object target, string source, Type type, bool replaceArrays = false)
{
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);
}