0

I am consuming a web service that will calculate tax. The problem is I don't always get the data back in exactly the same formatn (see example below). When I deserialize the data my code throws an exception. Any tips on what I can do to allow the deserialization to handle a single element or an array of a single element? FYI, I get back a lot more data in addition to the tax, but I am only showing the tax part to keep it simple.

Sometimes I get the data like this:

{
    "data": {
        "tax": [{
            "amount": 0.00,
            "category": 0.0
        }]
    }
}

Sometimes I get it like this:

{
    "data": {
        "tax": {
            "amount": 336.01,
            "category": 0.0
        }
    }
}

Here is my class:

public class Tax
{
    public float amount { get; set; }
    public float category{ get; set; }
}

I am thinking about adding an [XmlIgnore] attribute and manually deserailizing to get the tax data, but I would like to stay away from that if possible.

BriceTRockindale
  • 309
  • 1
  • 4
  • 15
  • 1
    Here: http://stackoverflow.com/a/18997172/126995 – Soonts Mar 01 '16 at 22:47
  • First one is **a tax array**, and latter is **a single item**. Quick and easy way is to use **try catch block**. If one serialization method fails, use the second one. By the way, what API do you use for calculating tax *(I'm also looking for one)*? – Win Mar 01 '16 at 22:47
  • Also, never keep money amounts in float or double variables. Floating-point data types aren’t for money. Use this instead: https://msdn.microsoft.com/en-us/library/system.decimal(v=vs.110).aspx – Soonts Mar 01 '16 at 22:50
  • Instead of using exceptions to switch on what form of data you have, it might be slightly less clunky to search the string for a bracket '[' indicating an array. BTW: The best solution would be to have the service return data in a consistent format. – Steve Wellens Mar 01 '16 at 22:53

3 Answers3

0

Make two (or more) different classes, then use the one that doesn't throw an exception when you deseralize.

It looks like you could deseralize the array data using this class:

public class data
{
    public Dictionary<string, double> tax { get; set; }
}

If that class successfully deserializes, you can then copy it over to the tax class, either manually, or by using Reflection.

Dave
  • 4,375
  • 3
  • 24
  • 30
0

Not sure how XmlIgnore would help with your JSON serialization, but i would suggest using Newtonsoft.Json to deserialize your payload to JObject. Then you can use Linq to JSON to investigate the result and perhaps manually instantiate your own object based on the type of "tax" property (JArray or JObject)

see LINQ to JSON for more info.

hnafar
  • 612
  • 8
  • 19
0

I'd use JSON.Net (link to nuget). Then I'd get a JObject from JObject.Parse method and check whether the relevant child element is JObject or JArray. Then, I'd convert it to your data class (or a dynamic type)

dynamic taxData;
var json = JObject.Parse(response);
var rawTaxData = json["data"]["tax"];

if (rawTaxData is JObject)
{
    taxData = JsonConvert.DeserializeObject(rawTaxData);
}
else if (rawTaxData is JArray)
{
    var actualData = rawTaxData [0];
    taxData = JsonConvert.DeserializeObject(actualData);
}

Also, just to be sure that your server actually returned data and not, for example, error message, use TryGetValue:

JToken dataToken;
if (!json.TryGetValue("data", out dataToken))
{
    var rawTaxData = dataToken["tax"];
    // ...
}
Amadeusz Wieczorek
  • 3,139
  • 2
  • 28
  • 32