1

The web service I consume responces with json data.

it gives resultObject as array: resultObject:[{object1}, {object2},...] if there more then one object and it returns resultObject:{object1} if there only one object.

for serializing in .NET I created a "static" structure of classes to map json schema. But if in one case i've got an array (list) of objects an in other case just one object, how is it possible to handle this situation?

WHITECOLOR
  • 24,996
  • 37
  • 121
  • 181
  • It probably depends on the serializer you choose, but if you say that resultObject is either a single instance of a given class (C) or an array of C I don't suppose you have other options than deserializing into `dynamic` or `object` and test the type using the `is` operator. Which serializer do you use? – faester May 01 '11 at 20:11
  • Nice question, unfortunate they respond with an array in one scenario and an object in the other. All to save 2 characters lol. Looking forward to seeing the answers. – John Hoven May 01 '11 at 20:18

2 Answers2

1

I have found a plethora of ugly solutions to this one, but so far goes:

If you use the System.Web.Script.Serialization.JavaScriptSerializer you have very limited control. If the result data type is simple, you could simply use the DeserializeObject method; it will translate everything into Dictionary and the "resultObject" property will in the first case be a Dictionary while the latter case will turn it into an array of such dictionary. It will not save you the headache of the final translation, but you will get the data into dictionaries which could be considered a first step.

I also attempted to use the KnownTypes and the DataContractJsonSerializer, but alas the datacontract serializer needs "hints" in the form of specially named properties to aid it deserializing. (Why am I using the KnownType attribute wrong?). This is a hopeless strategy if you don't have any control of the serialization which I guess is the case for you.

So now we are down to the butt-ugly solutions of which trial-and-error is my first choice: When using the ScriptSerializer the conversion will fail with an InvalidOperationException if anything is wrong. I then created two data types one with data-as-arrays and one where data is a single instance (the DataClass is my invention since you do not specify the data types):

    [DataContract]
    public class DataClass
    {
        [DataMember]
        public string FirstName { get; set; }
        [DataMember]
        public int BirthYear { get; set; }

        public override string ToString()
        {
            return "FirstName : '" + FirstName + "', BirthYear: " + BirthYear;
        }
    }

    [DataContract]
    public class ResultSingle 
    {
        [DataMember]
        public DataClass Data { get; set; }
    }

    [DataContract]
    public class ResultArray 
    {
        [DataMember]
        public List<DataClass> Data { get; set; }
    }

Using these data types it is possible to translate using

        JavaScriptSerializer jSer = new JavaScriptSerializer();
        var one = jSer.Deserialize<ResultSingle>(jsonWithSingleInstance);
        var many = jSer.Deserialize<ResultArray>(jsonWithArray);

But this of course require you to known the data type in advance and you get two different result types. Instead you could choose to always convert to ResultArray. If you get an exception you should convert as ResultSingle and then instantiate the ResultArray and manually add the data object to the Data list:

    static ResultArray ConvertJson(string json)
    {
        ResultArray fromJson;
        JavaScriptSerializer jSer = new JavaScriptSerializer();
        try
        {
            fromJson = jSer.Deserialize<ResultArray>(json);
            return fromJson;
        }
        catch (InvalidOperationException)
        {
            var single = jSer.Deserialize<ResultSingle> (json);
            fromJson = new ResultArray();
            fromJson.Data = new List<DataClass>();
            fromJson.Data.Add(single.Data);
            return fromJson;
        }
    }

    static void Main(string[] args)
    {
        var jsonWithSingleInstance = "{\"Data\":{\"FirstName\":\"Knud\",\"BirthYear\":1928}}";
        var jsonWithArray = "{\"Data\":[{\"FirstName\":\"Knud\",\"BirthYear\":1928},{\"FirstName\":\"Svend\",\"BirthYear\":1930}]}";

        var single = ConvertJson(jsonWithSingleInstance);
        var array = ConvertJson(jsonWithArray);
    }

I do not say this is a beautiful solution (it isn't), but it should do the job.

You could also look at json.net which seem to be the json serializer of choice in .NET: How to install JSON.NET using NuGet?

Community
  • 1
  • 1
faester
  • 14,886
  • 5
  • 45
  • 56
  • Faester, thank you for your responce. My problem is worse in this case: the web service has this dynamic json "feature" for all nested collections. So we have not just two data structure variants, but much more, besides structure it self is not simple one. To have several variants for structure in code definitely isn't the most elegant solution. My solution for now is to correct json serialized string (insert brackets [] where i need them) - its verry ugly but its working. – WHITECOLOR May 03 '11 at 09:21
  • Conserning the problem in general, are ther any standards that say thay that it isn't right to have such "dynamic structure" for json collection? All examples/case that i've seen before had collecton (array) brackets ([]) even there was only one element in a collection. Should my service provider fix this kind of behaviour of its service or it is acceptable by standards? – WHITECOLOR May 03 '11 at 09:22
  • I think you service provider should always provide a collection, even if it only contains a single element; you don't have many chances of making a solid solution otherwise. By I think that one problem with json is that there are more conventions than standards; in a traditional SOAP service you would have a hard definition of the data in a WSDL, which is not the case here. (Not that I prefer SOAP..) – faester May 03 '11 at 11:09
0

Well, my service provider finally said that it is really a bug.

http://jira.codehaus.org/browse/JETTISON-102

says that is it because of java version that they use.

WHITECOLOR
  • 24,996
  • 37
  • 121
  • 181