1

I have an object in .net that is mostly for the purpose of receiving some json. It generally works very nicely, but when there is a single item in an array of numbers the json library converts this to a single number and not an array with a single item. .net throws this out as an error as it is a single int32 instead of an array of int32s i tried converting to json.net but this had not surprisingly the same error

as far as i can think there is no way to have an alternative definition in my object, is there?

below is the definition of my object

public class EnquiryModel
{
    public string Name;
    public string Email;
    public string Phone;
    public string JobCode;
    public string Message;
    public int ReferralSource;
    public Dictionary<string, int> PickList;
    public int[] Studios;
    public int[] Services;
    public string[] BookingEnquiries;
}

and here is the code i use to populate it

using Newtonsoft.Json;
EnquiryModel enq = JsonConvert.DeserializeObject<EnquiryModel>(json);

previously I used

using System.Web.Script.Serialization;
JavaScriptSerializer j = new JavaScriptSerializer();
EnquiryModel enq = j.Deserialize<EnquiryModel>(json);

they both produce the same error

not sure what the best way to avoid this problem would be

when it is serialised on the client the arrays with a single item are converted to a single number not sure why that is either :) ?

UPDATED AS SOLVED

the answer marked as the solution below worked really well - thank you :)

there was a couple of tiny changes I had to make which I thought were worth sharing

firstly I found it was passed as an Int64 so my check is for both types with an or

also I had some code that used this object and because the public variable was no longer an array but an object I had to add a cast to the usage so:

foreach (int studio in enq.Studios)

had to change to

foreach (int studio in (Int32[])enq.Studios)

this is the full source of the object now it would be good if there were some way to generalise the repeated code to make it easier to read but that may well be gold-plating :)

public class EnquiryModel
{
    public string Name;
    public string Email;
    public string Phone;
    public string JobCode;
    public string Message;
    public int ReferralSource;
    public Dictionary<string, int> PickList;
    //allow the arrays of 1 to many values to be submitted as a single value
    // instead of a single item in an array
    private string[] bookingEnquiries;
    public object BookingEnquiries
    {
        get { return bookingEnquiries; }
        set
        {
            if (value.GetType() == typeof(string))
            {
                bookingEnquiries = new string[] { (string)value };
            }
            else if (value.GetType() == typeof(string[]))
            {
                bookingEnquiries = (string[])value;
            }
        }
    }
    private int[] studios;
    public object Studios
    {
        get { return studios; }
        set
        {
            if (value.GetType() == typeof(Int32) || value.GetType() == typeof(Int64))
            {
                studios = new Int32[] { (Int32)value };
            }
            else if (value.GetType() == typeof(Int32[]))
            {
                studios = (Int32[])value;
            }
        }
    }
    private int[] services;
    public object Services
    {
        get { return services; }
        set
        {
            if (value.GetType() == typeof(Int32) || value.GetType() == typeof(Int64))
            {
                services = new Int32[] { (Int32)value };
            }
            else if (value.GetType() == typeof(Int32[]))
            {
                services = (Int32[])value;
            }
        }
    }

}
John C Scott
  • 146
  • 11
  • 1
    Show us how your are constructing your json object. That's where the problem is most likely. – Ryan Bennett Jan 07 '13 at 15:46
  • yes definitely it would be better if the json wasn't generated like that, but apparently this is valid - so i do have to accept this and i can see it's quite logical to allow this, it's also beyond my control – John C Scott Jan 07 '13 at 21:05
  • I don't think the problem is related to how you are deserializing - I think the problem lies in the json itself once it gets to your deserializer. As in, its giving you an int, instead of an array with one int. – Ryan Bennett Jan 07 '13 at 21:25
  • the serializing is beyond my control, in the hands of another developer in another organisation, he tells me that the json he uses automatically makes this "correction" if an array with a single item is submitted it converts this to a single number. i have seen the source and seen that the library is doing this and can replicate it. i could insist the json comes in the expected format and force a change at the client end, but if this is a real issue then it feels the good solution is to accept this valid input also. – John C Scott Jan 08 '13 at 06:59

2 Answers2

2

I would make the variables p[rivate and expose them through getters and setters. In the setter, you can evaluate the property sent in and set it appropriately.

    private Int32[] numbers;

    public object Numbers
    {
        get { return numbers; }
        set
        {
            if (value.GetType() == typeof(Int32))
            {
                numbers = new Int32[] { (Int32)value };
            }
            else if (value.GetType() == typeof(Int32[]))
            {
                numbers = (Int32[])value;
            }
        }
    }
Brian P
  • 1,569
  • 13
  • 23
  • that looks like a logical explanation... thank you in this case would the code to set it remain the same i.e. EnquiryModel enq = JsonConvert.DeserializeObject(json); – John C Scott Jan 07 '13 at 18:18
  • It should, because that method should just be assigning to the properties. Remember to mark as answer if this helped. – Brian P Jan 07 '13 at 18:38
  • yes I like this solution a lot it's elegant and feels right - I'll try it out tomorrow - and will mark as the answer – John C Scott Jan 07 '13 at 21:06
  • no this actually doesn't work because the typeof() is then object[] when the array is sent which won't cast to int[] – John C Scott Feb 25 '13 at 14:30
  • Odd. Worked just fine for me. – Brian P Feb 25 '13 at 15:50
1

I feel you will need to write your own wrapper which will check that if a single item of type T exists, it converts it to new T[]{item}. You can use JSON.NET's JObject class.

JObject o = JObject.Parse(response);

and evaluate o for the particular property you are looking for.

prthrokz
  • 1,120
  • 8
  • 16
  • i had thought about this, i did just wonder if there was a better way to do this that wouldn't generate lots of extra code to be maintained if there was a way to have an alternative constructor, a setter that could somehow take an alternatively typed initialiser, that feels like the right solution – John C Scott Jan 07 '13 at 21:03