Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

218
Vistas
Uso de convertidores personalizados Newtonsoft.JSON para leer json con diferentes entradas

Estoy usando NewtonSoft.Json para leer/escribir nuestros datos como json. Un ejemplo (muy simplificado) de esto es:

 { "$type": "MyNamespace.LandingEvent, MyAssembly", "TimeOfLanding": "2021-04-11T15:00:00.000Z", "AirportName": "KLAX", "AirportRunway": "25L" }

Con una clase C# DTO que imita las propiedades. Tenga en cuenta que usamos TypeNameHandling .

Queremos cambiar nuestra clase de C# a una configuración más compleja:

 class Airport { public string Name { get; set; } public string Runway { get; set; } } class LandingEvent { public DateTime TimeOfLanding { get; set; } public Airport Airport { get; set; } }

lo que resultará en que los nuevos datos se escribirán en JSON como:

 { "$type": "MyNamespace.LandingEvent, MyAssembly", "TimeOfLanding": "2021-04-11T15:00:00.000Z", "Airport": { "Name": "KLAX", "Runway": "25L" } }

Pero aún necesitamos poder leer los datos JSON antiguos y analizarlos en la nueva estructura de clases. Y esto es con lo que lucho actualmente.

Sé que el camino a seguir es probablemente un JsonConverter especializado. Tengo un par de preguntas al respecto:

  1. ¿Cómo leo la propiedad $type e instancia el tipo correcto? (mi método CanConvert() recibe el nombre de una clase base (debido a que el contexto real es más complejo que este ejemplo).
  2. Solo quiero hacer una lectura personalizada, si existe la propiedad AirportName . ¿Cómo recurro a la deserialización predeterminada, si este no es el caso?

Editar: algunas aclaraciones están en orden. Si creo un JsonConverter personalizado, CanConvert recibirá el tipo EventBase , pero $type en realidad puede contener "MyNamespace.LandingEvent, MyAssembly" o "MyNamespace.TakeoffEvent, MyAssembly" . Por lo tanto, probablemente necesite crear una instancia del objeto devuelto yo mismo en función de este valor. Aunque no estoy seguro de cómo.

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

Puede usar un JsonConverter personalizado para realizar una doble función en el manejo de los tipos de eventos polimórficos y los diferentes formatos JSON. A continuación se muestra un ejemplo. Funciona cargando los datos en un JObject , donde puede leer la propiedad $type e instanciar el tipo de evento correcto. A partir de ahí, intentará completar el objeto de evento desde el JSON. Si el Airport no puede deserializarse, intentará leer las propiedades heredadas del aeropuerto y completar una nueva instancia del Airport a partir de eso.

 class EventConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(BaseEvent).IsAssignableFrom(objectType); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject obj = JObject.Load(reader); string type = (string)obj["$type"]; BaseEvent baseEvent; if (type.Contains(nameof(TakeoffEvent))) { baseEvent = new TakeoffEvent(); } else { baseEvent = new LandingEvent(); } serializer.Populate(obj.CreateReader(), baseEvent); if (baseEvent.Airport == null) { baseEvent.Airport = new Airport { Name = (string)obj["AirportName"], Runway = (string)obj["AirportRunway"] }; } return baseEvent; } public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }

Nota: esto supone que la estructura de su clase en realidad se ve así:

 class Airport { public string Name { get; set; } public string Runway { get; set; } } class BaseEvent { public Airport Airport { get; set; } } class TakeoffEvent : BaseEvent { public DateTime TimeOfTakeoff { get; set; } } class LandingEvent : BaseEvent { public DateTime TimeOfLanding { get; set; } }

Para usar el convertidor, agréguelo a la colección Converters en JsonSerializerSettings y pase la configuración a DeserializeObject() :

 var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects, Converters = new List<JsonConverter> { new EventConverter() } }; var baseEvent = JsonConvert.DeserializeObject<BaseEvent>(json, settings);

Aquí hay una demostración funcional: https://dotnetfiddle.net/jSaq4T

Ver también: Adición de soporte de compatibilidad con versiones anteriores para una estructura JSON más antigua

over 4 years ago · Santiago Trujillo Denunciar

0

Las clases cambian, este tipo de cadenas Json cambian y obtendrán funciones adicionales en futuras versiones. Seguirás ajustando tus declaraciones. Con Newtonsoft, puede agregar controladores personalizados para la herencia de clases variables y seguir usando la deserialización, pero tendrá que mantener ese código.

Para Json dinámico, me resulta más fácil usar JObject, JArray y JToken en su lugar, para analizar libremente una cadena Json. Especialmente si solo estás interesado en algunos de los campos.

Solo puedo darte un ejemplo, creo que esto está (un poco) relacionado con tu proyecto, pero no es la misma parte (smiley)

Utilizo el siguiente código para decodificar parte de un archivo de objeto 3d glTF producido por Blender en formato convertido a MSFS. Este formato similar a Json consta de secciones . Cada sección Json se parece a esto,

 "asset" : { "extensions" : { "ASOBO_normal_map_convention" : { "tangent_space_convention" : "DirectX" } }, "generator" : "Extended Khronos glTF Blender I/O v1.0.0", "version" : "2.0" },

.. pero estas secciones y sus campos son en su mayoría opcionales y en algunos GLtf no se completan. No es "serializable o deserializable" para las clases.

declaro algunos

 public JObject AssetObject;

.. completándolo desde Json string sJson de la siguiente manera:

 dynamic stuff = JObject.Parse(sJson); var pp = stuff.Children(); Dictionary<string, bool> d = new Dictionary<string, bool>(); foreach (JProperty jo in pp) d[jo.Name] = true; // all sections string cSection= "asset"; if (!d.ContainsKey(cSection)) { LogLine(98, "Warning: BPG Json has no " + cSection + " section."); return false; } else { AssetObject = (JObject)stuff[cSection]; ParseGLBAsset(); }

Observe el uso de una declaración dinámica al principio, una sección aterrizará en JObject a través de cast. Guardo las diversas partes de la sección en propiedades de cadena. El análisis en sí tiene lugar en ParseGLBAsset(), esta función tiene el siguiente aspecto:

 public void ParseGLBAsset() { foreach (JProperty jbp in AssetObject.Children()) if (jbp.Name == "generator") { GLBGenerator = jbp.Value.ToString(); } else if (jbp.Name == "extensions") { GLBAssetExtensions = jbp.Value.ToString(); LogLine(0, "Asset extensions: " + GLBAssetExtensions); } else if (jbp.Name == "version") { GLBVersion = jbp.Value.ToString(); } LogLine(1, "Found asset.generator=" + GLBGenerator); LogLine(1, "Found asset.version=" + GLBVersion); }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda