2

My project contains too much calls to rest api and sometime i get json array and sometime json object.

Current I have to write same repeated code for each of call to determine the response json is array or object.

So i faced below errors because i dont know the incoming json type.

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'userList' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array

OR

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[MvcSumit1.Models.User]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.

So to get rid of this problem I want generic method that can handle both of above scenarios.

4
  • 1
    As far as I know, C# do not support JSON (to understand the meaning: there is no JSON library build in framework). Write at least what type of JSON library you use. (You would never see this error with the JSON library I use.) Commented Sep 27, 2018 at 6:30
  • possible duplicate, can you please check this stackoverflow.com/questions/20620381/… Commented Sep 27, 2018 at 6:38
  • @Julo i used Newtonsoft.Json. Commented Sep 27, 2018 at 6:40
  • 1
    @KarthickTrichyChandrasekaran, i want generic method so i can pass only type and it gives me a result . Commented Sep 27, 2018 at 6:41

2 Answers 2

3

I want generic method that can handle both of above scenarios.

The below generic method that can parse your incoming json to object or List<object>.

public class Utility
{
    public static object JsonParser<T>(string json)
    {
        try
        {
            JToken jToken = JToken.Parse(json);

            if (jToken is JArray)
                return jToken.ToObject<List<T>>();
            else if (jToken is JObject)
                return jToken.ToObject<T>();
            else
                return "Unable to cast json to unknown type";
        }
        catch (JsonReaderException jex)
        {
            return jex.Message;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }
}

You can use above generic method like below. I created a console app for your demonstration purpose.

class Program
{
    static void Main(string[] args)
    {
        var result = Utility.JsonParser<User>("You json either object or array");

        if (result is List<User>)
        {
            var userList = result as List<User>;
            userList.ForEach(user => Console.WriteLine($"Id: {user.Id},  Name: {user.Name}, Age: {user.Age}"));
        }
        else if (result is User)
        {
            var user = result as User;
            Console.WriteLine($"Id: {user.Id},  Name: {user.Name}, Age: {user.Age}");
        }
        else if (result is string)
        {
            Console.WriteLine(result);
        }

        Console.ReadLine();
    }
}

Sample class is used to deserialize your json.

public class User
{
    public string Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Output:

1) By using json with array of objects

string json1 = @"[{'Id':'1','Name':'Mike','Age':43},{'Id':'2','Name':'Anna','Age':56}]";

enter image description here

2) By using json with object only.

string json2 = @"{'Id':'3','Name':'John','Age':24}";

enter image description here


Alternative

The below generic method that can parse your incoming json to object or List<object> and return List<object>.

public class Utility
{
    public static List<T> JsonParser<T>(string json)
    {
        JToken jToken = JToken.Parse(json);

        if (jToken is JArray)
        {
            return jToken.ToObject<List<T>>();
        }
        else if (jToken is JObject)
        {
            List<T> lst = new List<T>();
            lst.Add(jToken.ToObject<T>());
            return lst;
        }
        else
            return new List<T>();
    }
}

You can use above generic method like below.

class Program
{
    static void Main(string[] args)
    {
        var userList = Utility.JsonParser<User>("You json either object or array");

        if (userList.Count > 0)
        {
            userList.ForEach(user => Console.WriteLine($"Id: {user.Id},  Name: {user.Name}, Age: {user.Age}"));
        }
        else
        {
            //Do code here if your list is empty
        }

        Console.ReadLine();
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

this is i was looking for thanks it works and it solved my problem :)
Here's my opinion, the method should return List<T> regardless. It should internally deserialize the single object and then put it into a list, returning a list with 1 elements. Since the caller would need to handle the list scenario anyway, it really depends on whether the caller actually need to know if the json contained a single object or an array with a single object. If that doesn't matter, I would return List<T> instead of object.
@LasseVågsætherKarlsen, Thanks for your suggestion, I'll definitely update my answer whenever i get enough time, thanks once again :)
0

In case we have to deal with different types not just by Array or object, following is my approach: (note I am using Newtonsoft.Json)

methods1

public bool TryDeserialize(string json, out object target, params Type[] types)
{            
    foreach (Type type in types)
    {
        try
        {
            target = JsonConvert.DeserializeObject(json, type);
            return true;
        }
        catch (Exception)
        {                    
        }
    }
    target = null;
    return false;
}

then use it like:

 object obj = null;
 Type[] types = new Type[] { typeof(TypeA), typeof(List<TypeB>) };

 if (TryDeserialize(json, out obj, types))
 {
     if (obj is TypeA)
     {
         var r = obj as TypeA;
     }
     else
     {
         var r = obj as List<TypeB>;
     }
 }

or method 2

public bool TryDeserialize<T1, T2>(string json, out object target)
{            

    try
    {
        target = JsonConvert.DeserializeObject<T1>(json);
        return true;
    }
    catch (Exception)
    {
    }

    try
    {
        target = JsonConvert.DeserializeObject<T2>(json);
        return true;
    }
    catch (Exception)
    {
        target = null;
        return false;
    }
}

and use it like:

object obj = null;
if (TryDeserialize<TypeA, List<TypeB>>(json, out obj))
{
    if (obj is TypeA)
    {
        var r = obj as TypeA;
    }
    else
    {
        var r = obj as List<TypeB>;
    }
}

Comments

Your Answer

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