c# dynamic json.net key

c# - ¿Cómo deserializar un objeto hijo con nombres de clave dinámicos(numéricos)?



dynamic json.net (2)

Tienes un par de problemas:

  • Su JSON tiene un nivel adicional de anidamiento, con el objeto raíz que contiene una sola propiedad "users" :

    { "users" : { ... } }

    Su modelo de datos debe reflejar esto.

  • Su objeto "users" tiene una mezcla de nombres de propiedad conocidos y desconocidos. La pregunta Deserializar json con campos conocidos y desconocidos aborda una situación similar, sin embargo, en su caso, sus propiedades desconocidas siempre tienen un esquema fijo y sus valores deben deserializarse en un diccionario de POCO, específicamente la clase User . Por lo tanto, las respuestas allí no satisfacen sus necesidades ni la funcionalidad [JsonExtensionData] .

El siguiente convertidor permite que las propiedades desconocidas se deserialicen en un contenedor con tipo , en lugar de en un diccionario de tipos arbitrarios:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] public class JsonTypedExtensionDataAttribute : Attribute { } public class TypedExtensionDataConverter<TObject> : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(TObject).IsAssignableFrom(objectType); } JsonProperty GetExtensionJsonProperty(JsonObjectContract contract) { try { return contract.Properties.Where(p => p.AttributeProvider.GetAttributes(typeof(JsonTypedExtensionDataAttribute), false).Any()).Single(); } catch (InvalidOperationException ex) { throw new JsonSerializationException(string.Format("Exactly one property with JsonTypedExtensionDataAttribute is required for type {0}", contract.UnderlyingType), ex); } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var jObj = JObject.Load(reader); var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType); var extensionJsonProperty = GetExtensionJsonProperty(contract); var extensionJProperty = (JProperty)null; for (int i = jObj.Count - 1; i >= 0; i--) { var property = (JProperty)jObj.AsList()[i]; if (contract.Properties.GetClosestMatchProperty(property.Name) == null) { if (extensionJProperty == null) { extensionJProperty = new JProperty(extensionJsonProperty.PropertyName, new JObject()); jObj.Add(extensionJProperty); } ((JObject)extensionJProperty.Value).Add(property.RemoveFromLowestPossibleParent()); } } var value = existingValue ?? contract.DefaultCreator(); using (var subReader = jObj.CreateReader()) serializer.Populate(subReader, value); return value; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType()); var extensionJsonProperty = GetExtensionJsonProperty(contract); JObject jObj; using (new PushValue<bool>(true, () => Disabled, (canWrite) => Disabled = canWrite)) { jObj = JObject.FromObject(value, serializer); } var extensionValue = (jObj[extensionJsonProperty.PropertyName] as JObject).RemoveFromLowestPossibleParent(); if (extensionValue != null) { for (int i = extensionValue.Count - 1; i >= 0; i--) { var property = (JProperty)extensionValue.AsList()[i]; jObj.Add(property.RemoveFromLowestPossibleParent()); } } jObj.WriteTo(writer); } [ThreadStatic] static bool disabled; // Disables the converter in a thread-safe manner. bool Disabled { get { return disabled; } set { disabled = value; } } public override bool CanWrite { get { return !Disabled; } } public override bool CanRead { get { return !Disabled; } } } public struct PushValue<T> : IDisposable { Action<T> setValue; T oldValue; public PushValue(T value, Func<T> getValue, Action<T> setValue) { if (getValue == null || setValue == null) throw new ArgumentNullException(); this.setValue = setValue; this.oldValue = getValue(); setValue(value); } #region IDisposable Members // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class. public void Dispose() { if (setValue != null) setValue(oldValue); } #endregion } public static class JsonExtensions { public static TJToken RemoveFromLowestPossibleParent<TJToken>(this TJToken node) where TJToken : JToken { if (node == null) return null; var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault(); if (contained != null) contained.Remove(); // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should if (node.Parent is JProperty) ((JProperty)node.Parent).Value = null; return node; } public static IList<JToken> AsList(this IList<JToken> container) { return container; } }

Luego úsalo en tus clases de la siguiente manera:

class RootObject { [JsonProperty("users")] public Users Users { get; set; } } [JsonConverter(typeof(TypedExtensionDataConverter<Users>))] class Users { public Users() { this.UserTable = new Dictionary<string, User>(); } [JsonProperty("parentname")] public string ParentName { get; set; } [JsonTypedExtensionData] public Dictionary<string, User> UserTable { get; set; } } class User { public string name { get; set; } public string state { get; set; } public string id { get; set; } }

Escribí el convertidor de una manera bastante general para que pueda reutilizarse. Un convertidor que esté codificado para el tipo Users requeriría menos código.

¿Cómo puedo deserializar debajo de la estructura json usando newtonsoft json.net en .net?

{ "users" : { "parentname":"test", "100034" : { "name" : "tom", "state" : "WA", "id" : "cedf-c56f-18a4-4b1" }, "10045" : { "name" : "steve", "state" : "NY", "id" : "ebb2-92bf-3062-7774" }, "12345" : { "name" : "mike", "state" : "MA", "id" : "fb60-b34f-6dc8-aaf7" } } }

Intenté debajo del código pero no funciona. Recibí el error ''Error al convertir el valor "prueba" para escribir'' ConsoleApplication2.User '' Ruta ''users.parentname'', línea 5, posición 35. ''

class Program { static void Main(string[] args) { string json = @" { ""users"": { ""parentname"":""test"", ""10045"": { ""name"": ""steve"", ""state"": ""NY"", ""id"": ""ebb2-92bf-3062-7774"" } } }"; RootObject root = JsonConvert.DeserializeObject<RootObject>(json); } } class RootObject { public string ParentName { get; set; } public Dictionary<string, User> users { get; set; } } class User { public string name { get; set; } public string state { get; set; } public string id { get; set; } public string ParentName { get; set; } }

Por favor recomiende.


Tu Json tiene que verse así:

{ "ParentName":"test", "users":{ "10045":{ "name":"steve", "state":"NY", "id":"ebb2-92bf-3062-7774", "ParentName":"someOtherName" } } }

Para deserializarlo con su estructura de clase dada:

class RootObject { public string ParentName { get; set; } public Dictionary<string, User> users { get; set; } } class User { public string name { get; set; } public string state { get; set; } public string id { get; set; } public string ParentName { get; set; } }

Ahora puede deserializar la cadena Json con:

var root = JsonConvert.DeserializeObject<RootObject>(json);