Question

I send requests to API and have two responses.

First:

{"response": [{...}, {...}]}

Second:

{"response": {"count": 0, "items": [{...}, {...}]}}

Can I create one class for two cases? I use C# and Json.NET.

Was it helpful?

Solution

Yes, you can use a custom JsonConverter detect the JSON format and deserialize into the same class(es). Below is a converter that can handle both formats. It assumes that you are going to deserialize into a List<Item>.

class ItemListConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<Item>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken response = JToken.Load(reader)["response"];
        if (response.Type == JTokenType.Array)
        {
            return response.ToObject<List<Item>>();
        }
        else
        {
            return response["items"].ToObject<List<Item>>();
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Here is a demo showing how to use the converter:

class Item
{
    public int Id { get; set; }
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        string json1 = @"
        {
            ""response"" :
            [
                { ""Id"" : 1, ""Name"" : ""Foo"" },
                { ""Id"" : 2, ""Name"" : ""Bar"" },
            ]
        }";

        DeserializeAndDump(json1);

        string json2 = @"
        {
            ""response"" :
            {
                ""count"" : 2,
                ""items"" :
                [
                    { ""Id"" : 3, ""Name"" : ""Fizz"" },
                    { ""Id"" : 4, ""Name"" : ""Buzz"" },
                ]
            }
        }";

        DeserializeAndDump(json2);
    }

    private static void DeserializeAndDump(string json)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.Converters.Add(new ItemListConverter());

        List<Item> list = JsonConvert.DeserializeObject<List<Item>>(json, settings);

        foreach (Item item in list)
        {
            Console.WriteLine("Id: " + item.Id + ", Name: " + item.Name);
        }
    }
}

Here is the output of the above:

Id: 1, Name: Foo
Id: 2, Name: Bar
Id: 3, Name: Fizz
Id: 4, Name: Buzz

OTHER TIPS

First, if you are not aware of it, there is this online tool http://json2csharp.com/ where you can generate your C# class from your JSON string. I think it could be better to use two different classes. Is there a specific reason to use only one?

You can use JsonExtensionData attribute

Only declare the properties you’re interested in and let extension data do the rest.

public class CustomerInvoice
{
  // we're only modifing the tax rate
  public decimal TaxRate { get; set; }

  // everything else gets stored here
  [JsonExtensionData]
  private IDictionary<string, JToken> _additionalData;
}

string json = @"{
  'HourlyRate': 150,
  'Hours': 40,
  'TaxRate': 0.125
}";

var invoice = JsonConvert.DeserializeObject<CustomerInvoice>(json);

// increase tax to 15%
invoice.TaxRate = 0.15m;

string result = JsonConvert.SerializeObject(invoice);
// {
//   'TaxRate': 0.15,
//   'HourlyRate': 150,
//   'Hours': 40
// }

Using extension data to round-trip JSON like this also means you don’t need to worry about third-party sources adding additional JSON because it will automatically be preserved when serializing/deserializing. Nifty.

If you don’t want extension data serialized (or deserialized) then disable that functionality by setting WriteData and ReadData properties on ExtensionDataAttribute to false.

Reference: Json.NET 5.0 Release 7 – Immutable Collections

or custom JsonConvert, so look here Deserialize JSON not working with JSON.NET

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top