0

So in my app I have to get a JSON string. It can be a City or a List of Cities.

In the City class I have this:

public class City
{
    public string id { get; set; }
    public string country { get; set; }
    public string region { get; set; }
    public string city { get; set; }
    public string latitude { get; set; }
    public string longitude { get; set; }
    public string comment { get; set; }
    public bool wasThereAnError { get; set; }

    public class CityResponse
    {
        public string status { get; set; }
        public string message { get; set; }
        //public City result { get; set; }
        public List<City> result { get; set; }
    }

So it uses the List result to store data. This works fine when I get a JSON array back, it stores them all easily. However if I just query for 1 city, I get an exception about it needing an array. Here is the code for my call:

    async private Task<City.CityResponse> GetCityInformation(string url)
    {
        var client = new HttpClient();
        var response = await client.GetAsync(new Uri(url));
        string result = await response.Content.ReadAsStringAsync();
        var cityRoot = JsonConvert.DeserializeObject<City.CityResponse>(result);

        return cityRoot;
    }

Is it possible for me to store 1 city in the list too? Or do I need to make a seperate cities class or how do I go about this? Thanks

15
  • 2
    See here: stackoverflow.com/questions/11126242/…, both the accepted and the next answer after it will give you the solution Commented Nov 14, 2013 at 1:08
  • 1
    I am not sure... If you add an extra property City Result (different spell) into CityResponse, would it be populated with a single value? So you can handle setter then Commented Nov 14, 2013 at 1:47
  • 1
    @AndyOHart is it possible to override/extend default deserializer? Though i'd prefere to force datasource send correct types... Commented Nov 14, 2013 at 2:01
  • 1
    For the single city case, can you have the city formatted as an array with one element? It seems like the remote server is a little loose with its contract. Commented Nov 14, 2013 at 2:03
  • 1
    @AndyOHart he means the server that gives you json sends a single value instead of an array with 1 value, so you should do something with that server :) Commented Nov 14, 2013 at 2:12

2 Answers 2

1

Here's a small solution based on Jim's answer.

class CityResponse
{
    public string status { get; set; }

    public object result
    {
        get { return null; }
        set 
        {
            cities = new List<City>();

            if (value.GetType() == typeof(JArray))
            {
                cities = ((JArray)value).ToObject<List<City>>();
                foreach(var city in cities) city.ParentResponse = this; // Edit
                return;
            }

            if (value.GetType() != typeof(JObject)) 
                return;

            cities.Add(((JObject)value).ToObject<City>());
            foreach(var city in cities) city.ParentResponse = this; // Edit
        }
    }

    public string message { get; set; }

    public List<City> cities { get; internal set; }
}

Hope it helps!

PS: I don't know if the system that provides the JSON data is created by you, but having a member with an inconsistent type is bad design.

-- Edit --

In reply to a comment on this answer, asking on how to access the CityResponse from a City object, here's how I would do it:

I would add a new property to the City class, which would be meant for holding the parent CityResponse

public class City
{
    public string id { get; set; }

    ...

    public CityResponse ParentResponse { get; set;}
}

And then perform some minor changes to the setter, as seen in the original portion of the answer above.

Sign up to request clarification or add additional context in comments.

12 Comments

@AndyOHart The cities property is internally set when the JSON deserializer tries to set the result property (you'll notice that the setter for that property is explicitly defined). It is not actually expected to be present in the JSON object you receive.
@AndyOHart I would re-implement your ToString() override and then iterate through the results (cities) using a for or foreach loop, while printing them out.
@AndyOHart You can access it from the result of your GetCityInformation() call.
@AndyOHart No. In order to do so you would have to add a reference to the parent CityResponse class in a new property, preferably in the result setter.
@AndyOHart I edited the initial answer to contain more information. I should however note that accessing the rest of the City object from another City object for such a purpose is probably bad practice.
|
1

instead of:

public class CityResponse
    {
        public string status { get; set; }
        public string message { get; set; }
        public List<City> result { get; set; }
    }

try:

public class CityResponse
    {
        public string status { get; set; }
        public string message { get; set; }
        public string result { 
            get{ return null; }
            set{
                    // if 1st character is "[" then it's an array of City, otherwise a City object 
                    //depending on the above parse this string (which is like "{prop1: qqq, prop2: www}" 
                    // or like "[{prop1: qqq, prop2: www}, {prop1: eee, prop2: eee}]")
                    // by the existing serializer or other one 
                    // into City or array of cities
                    // if City, then convert in to array of cities
                    // and save result into realResult
            }
        }
        public List<City> realResult { get; set; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.