-2

I got this strange API response from external service:

{
    "Columns": {
      "1": {
        "Fuels": [
          "1",
          "10",
          "4",
          "4"
        ]
      },
...
      "6": {
        "Fuels": [
          "1",
          "4",
          "10"
        ]
      }
    }
}

By default, all converters (json -> to csharp model) does models like this:

public class _1
{
    public List<string> Fuels { get; set; }
}

public class _2
{
    public List<string> Fuels { get; set; }
}

public class _3
{
    public List<string> Fuels { get; set; }
}

public class _4
{
    public List<string> Fuels { get; set; }
}

public class Columns
{
    public _1 _1 { get; set; }
    public _2 _2 { get; set; }
    public _3 _3 { get; set; }
    public _4 _4 { get; set; }
}

But I want something like this:

public class Column
{
    public string Number { get; set; }
    public List<string> Fuels { get; set; }
}

I think it's a side developers fault with Json serialization, because Columns should be an Array, but it's an Objects :(

I need to somehow convert this to Array, maybe it is some Newtonsoft or default .NET Json converter attributes or something to do that without writing custom deserializer?
I'm using .NET 6.

hamaronooo
  • 471
  • 4
  • 20
  • `JObject.Parse(json)["Columns"].ToObject>().Values`? – Peter Csala Jun 20 '22 at 13:41
  • @PeterCsala is it possible to do by model attributes, to do not write some additional code for parsing? – hamaronooo Jun 20 '22 at 13:43
  • 2
    If you define your `Columns` property as `Dictionary` then it will work with the default json converter. Fiddle link: https://dotnetfiddle.net/SpK84a – Peter Csala Jun 20 '22 at 13:49
  • 1
    Does this answer your question? [json deserialization to C# with dynamic keys](https://stackoverflow.com/questions/65727513/json-deserialization-to-c-sharp-with-dynamic-keys) – Charlieface Jun 20 '22 at 13:51
  • 1
    @PeterCsala Thank you, idea with `Dictionary` helps, post answer and I will accept it. – hamaronooo Jun 20 '22 at 14:27

3 Answers3

0

try this

List<Column> columns = ((JObject)JObject.Parse(json)["Columns"]).Properties()
                    .Select(v => new Column(v.Name, v.Value["Fuels"].ToObject<List<string>>()))
                    .ToList();

class

public class Column
{
    public string Number { get; set; }
    private List<string> Fuels { get; set; }

    public Column(string number, List<string> fuels)

    {
        Number = number;
        Fuels = fuels;
    }
    public Column(){}
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • +rep, thanks much, but the way with `Dictionary` is better – hamaronooo Jun 20 '22 at 15:30
  • @hamaronooo why then you ask to make fuels private? – Serge Jun 20 '22 at 15:43
  • I have downvoted your answer because the OP is looking for an attribute based solution. Linq 2 json is not that. – Peter Csala Jun 20 '22 at 18:20
  • What about OP is looking private List Fuels? Do you think that OP really understand what he needs and what is better? I newer down vote any answers if they are working properly, doesn't matter what I am thinking that OP is thinking. It is always good to have an alternative solution. A list could fit better for somebody else who understands that a typed object is always better. – Serge Jun 20 '22 at 18:25
  • @PeterCsala I explained you already. Because your solution is wrong. It will not deserialize private List Fuels. Otherwise your solution is just a duplicate, since here 99 % Json answers are offering a Dictionary. I would be ashamed to offer this. – Serge Jun 20 '22 at 18:54
  • What private are you talking about? – Peter Csala Jun 20 '22 at 18:57
  • @PeterCsala Look at OP column class – Serge Jun 20 '22 at 19:02
  • @Serge I'm Sorry! It's my fault, typo... of course it's public :( – hamaronooo Jun 20 '22 at 19:10
  • Sorry but I don't get your reasoning. You have downvoted my, because the OP's code is not working. – Peter Csala Jun 20 '22 at 19:15
  • @PeterCsala I downvoted because your solution was not working with OP model but mine was working. But if you had not downvoted mine, I would never touch yours. As I told I never downvoting anybodys answer, since I understand that the person was trying his best. I only downvote in one case - when somebody copies my answer and posts it as it is his. – Serge Jun 20 '22 at 19:32
0

Json.Net can deserialize any object into a Dictionary<string, object>.

You can specialise the key's and value's types, in your case:

  • int
  • Column

Where Column is defined as

public class Column
{
   public List<string> Fuels {get; set;}
}

So, if you define your Columns property in your root class as Dictionary<int, Column> then it will work fine with the default json converter

public class Root
{
   public Dictionary<int, Column> Columns;
}

Imperative usage:

var result = JsonConvert.DeserializeObject<Root>(json).Columns;
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
-3
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class _1
{
    public List<string> Fuels { get; set; }
}

public class _6
{
    public List<string> Fuels { get; set; }
}

public class Columns
{
    public _1 _1 { get; set; }
    public _6 _6 { get; set; }
}

public class Root
{
    public Columns Columns { get; set; }
}
Ranjith.V
  • 316
  • 1
  • 7