Deserialize JSON file that has blocks in just one Model (class)

467 Views Asked by At

How can I deserialize a JSON file that has blocks in a single class? Is there a way that I can inform what is the parent block for the attribute and the attribute using the JSON annotation in Class?

The JSON is below:

{
    "Viagem": {
        "Id": 33333,
        "NumeroAtracacao": "22/2222",
        "NumeroViagem": "02002 00303",
        "Status": "DESATRACADO",
        "Joint": "UCLA UCLA",
        "Servico": "AMERICA CENTRAL",
        "MotivoEspera": "-",
        "LiberacaoRecebimento": "21/05/2018 07:00:00",
        "Navio": {
            "Nome": "MONTE CERVANTES",
            "Armador": {
                "Id": 0,
                "CodigoGeParcei": null,
                "Nome": "ALIANCA",
                "Sigla": "ALI",
                "CnpjCpf": null,
                "Endereco": null,
                "Cep": null,
                "Site": null
            },
            "ImagemNavio": ".......",
            "Comprimento": 272.08,
            "Lloyd": 9283186,
            "CallSign": "DHTK",
            "CapacidadeTeus": 5560,
            "Shortname": "MOCER"
        },
        "ChegadaPrevista": "27/05/2018 12:00:00",
        "AtracacaoPrevista": "29/05/2018 07:00:00",
        "SaidaPrevista": "30/05/2018 19:00:00",
        "DeadLine": "25/05/2018 12:00:00"
    }
}

And this is my class that I want to use to deserialize the JSON:

namespace WS_SantosBrasil.Model
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;

    [Table("Viagem")]
    public partial class Viagem
    {
        [Key]
        [Column(Order = 0)]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }  

        [Key]
        [Column(Order = 1)]
        [StringLength(50)]
        public string IdCtis { get; set; }

        [StringLength(20)]
        public string NumeroAtracacao { get; set; }

        [StringLength(20)]
        public string NumeroViagem { get; set; }

        [StringLength(50)]
        public string Status { get; set; }

        [StringLength(50)]
        public string Joint { get; set; }

        [StringLength(50)]
        public string Servico { get; set; }

        [StringLength(50)]
        public string MotivoEspera { get; set; }

        [StringLength(20)]
        public string LiberacaoRecebimento { get; set; }

        [StringLength(20)]
        public string ChegadaPrevista { get; set; }

        [StringLength(20)]
        public string AtracacaoPrevista { get; set; }

        [StringLength(20)]
        public string SaidaPrevista { get; set; }

        [StringLength(20)]
        public string DeadLine { get; set; }

        [StringLength(20)]
        public string Chegada { get; set; }

        [StringLength(20)]
        public string Atracacao { get; set; }

        [StringLength(20)]
        public string Saida { get; set; }

        [StringLength(20)]
        public string InicioOperacao { get; set; }

        [StringLength(20)]
        public string FimOperacao { get; set; }

        [StringLength(50)]
        public string TipoOperacao { get; set; }

        [StringLength(20)]
        public string CodigoCodesp { get; set; }

        public decimal? CaladoAtracacao { get; set; }

        public decimal? CaladoDesatracacao { get; set; }

        [StringLength(20)]
        public string NumeroViagemImportacao { get; set; }

        [StringLength(20)]
        public string NumeroViagemExportacao { get; set; }

        [StringLength(20)]
        public string PrevisaoDescarga { get; set; }

        [StringLength(20)]
        public string PrevisaoEmbarque { get; set; }

        [StringLength(20)]
        public string PrevisaoRemocao { get; set; }

        [StringLength(50)]
        public string LocalAtracacao { get; set; }

        [StringLength(100)]
        public string Navio_Nome { get; set; }

        public string ImagemNavio { get; set; }

        public decimal? Navio_Comprimento { get; set; }

        [StringLength(20)]
        public string Navio_Lloyd { get; set; }

        [StringLength(50)]
        public string Navio_CallSign { get; set; }

        public int? Navio_CapacidadeTeus { get; set; }

        [StringLength(20)]
        public string Navio_Shortname { get; set; }

        public int? Armador_Id { get; set; }

        [StringLength(20)]
        public string Armador_CodigoGeParcei { get; set; }

        [StringLength(100)]
        public string Armador_Nome { get; set; }

        [StringLength(10)]
        public string Armador_Sigla { get; set; }

        [StringLength(20)]
        public string Armador_CnpjCpf { get; set; }

        [StringLength(100)]
        public string Armador_Endereco { get; set; }

        [StringLength(20)]
        public string Armador_Cep { get; set; }

        [StringLength(100)]
        public string Armador_Site { get; set; }

        public virtual ContainerViagem ContainerViagem { get; set; }
    }
}

How can I inform when deserializing the JSON for this class, that the attribute Nome_Navio, for example, is inside block Navio and that the JSON attribute is NOME?

3

There are 3 best solutions below

0
On

No, you don't want to map your JSON directly into a database entity class. You can go to great lengths and do some attribute and custom serializer logic, but that's a maintenance nightmare (what if the JSON or the entity's structure changes?).

Instead generate a class to deserialize this JSON into, and then map that class's fields to your entity.

1
On

are you sure you don't want to create a class to map it to as CodeCaster says?

public class Viagem 
{
    public int Id {get; set;}
    public string NumeroAtracacao {get; set;}
    public string Status {get; set;}
    public string Joint {get; set;}
    public string Servico {get; set;}
    public string MotivoEspera {get; set;}
    public Navio Navio {get; set;}
    public DateTime ChegadaPrevista {get; set;}
    public DateTime AtracacaoPrevista {get; set;}
    public DateTime SaidaPrevista {get; set;}
    public DateTime DeadLine {get; set;}
}

public class Navio 
{
    public string Nome {get; set;}
    public Armador Armador {get; set;}
    public string ImagemNavio {get; set;}
    public int Comprimento {get; set;}
    public int Lloyd {get; set;}
    public string CallSign {get; set;}
    public string CapacidadeTeus {get; set}
    public string Shortname {get; set;}
}

public class Armador 
{
    public int Id {get; set;}
    public object CodigoGeParcei {get; set;}
    public string Nome {get; set;}
    public string Sigla {get; set;}
    public object CnpjCpf {get; set;}
    public object Endereco {get; set;}
    public object Cep {get; set;}
    public object Site {get; set;}
}

you could then just do a straight

JsonConvert.DersializeObject<Viagem>(json); (if you're using Newtonsoft)

0
On

You should be able to use the JsonPathConverter class from Can I specify a path in an attribute to map a property in my class to a child property in my JSON? to do what you want.

To use it, first add a [JsonConverter] attribute to your Viagem class specifying the JsonPathConverter, like this:

[JsonConverter(typeof(JsonPathConverter))]
public partial class Viagem
{
    ...
}

Then, for each property that you want to deserialize from the JSON, add a [JsonProperty] attribute specifying its dot-separated path in the JSON. Here are a few examples:

    [JsonProperty("Viagem.Id")]
    public int Id { get; set; }

    [JsonProperty("Viagem.Status")]
    public string Status { get; set; }

    [JsonProperty("Viagem.Navio.Nome")]
    public string Navio_Nome { get; set; }

    [JsonProperty("Viagem.Navio.ImagemNavio")]
    public string ImagemNavio { get; set; }

    [JsonProperty("Viagem.Navio.Armador.Id")]
    public int? Armador_Id { get; set; }

    [JsonProperty("Viagem.Navio.Armador.Nome")]
    public string Armador_Nome { get; set; }

Then you can deserialize as you normally would, and it should "just work":

Viagem viagem = JsonConvert.DeserializeObject<Viagem>(json);

Here is a working demo: https://dotnetfiddle.net/repgUW

Note that if you need to serialize your model back to JSON, you will need to implement the WriteJson method in the converter. There is another answer in the linked question thread which suggests an implementation for that, but I have not tested it.