0

I have a list of objects in below json format. I would like to deserialize using below code. It is throwing unable to convert to object error. I have tried below three options, but didnt help. jsoninput is a IEnumerable<string>converted into json object using ToJson().

Error: {"Error converting value \"{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false,\"userType\":0,\"profilePrivacy\":1,\"chatPrivacy\":1,\"callPrivacy\":0}\" to type 'Api.Models.UserInfo'. Path '[0]', line 1, position 271."}

var requests1 = JsonConvert.DeserializeObject<UsersInfo>(jsoninput);
var requests2 = JsonConvert.DeserializeObject<IEnumerable<UserInfo>>(jsoninput);
var requests3 = JsonConvert.DeserializeObject<List<UserInfo>>(jsoninput);

//Below are my classes,
public class UsersInfo

{
    public List<UserInfo> UserInfoList { get; set; }
    public UsersInfo()
    {
        UserInfoList = new List<UserInfo>();
    }
}

public class UserInfo
{
    public string Id { set; get; }
    public string Name { set; get; }
    public string LastName { set; get; }
    public string ProfilePictureUrl { set; get; }
    public string SmallUrl { set; get; }
    public string ThumbnailUrl { get; set; }
    public string Country { set; get; }
    public bool IsInvalid { set; get; }
}

Below is my json object,

["{\"id\":\"11ef2c75-9a6d-4cef-8163-94daad4f8397\",\"name\":\"bracing\",\"lastName\":\"male\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}","{\"id\":\"318c0885-2720-472c-ba9e-1d1e120bcf65\",\"name\":\"locomotives\",\"lastName\":\"riddles\",\"profilePictureUrl\":null,\"smallUrl\":null,\"thumbnailUrl\":null,\"country\":null,\"isInvalid\":false}"]

Looping through individual items in json input and if i deserialize it like below, it works fine. But i want to deserialize the list fully. Note: jsoninput was a IEnumerable<string> before i convert in json object.

foreach (var re in jsoninput)
{
    var request0 = JsonConvert.DeserializeObject<UserInfo>(re);
}
Raj
  • 319
  • 1
  • 3
  • 18
  • Please provide the exact error you're seeing. – Jon Skeet Jun 16 '20 at 15:23
  • 3
    But fundamentally your JSON doesn't represent a list of objects - it represents a list consisting of a single string, which itself contains a JSON object. – Jon Skeet Jun 16 '20 at 15:24
  • Where did you take `jsonInput` from? Escaped like this, it is not a valid json (hence, the error) – Tu.Ma. Jun 16 '20 at 15:25
  • @JonSkeet How should i edit my code to deserialize it? – Raj Jun 16 '20 at 15:31
  • @Tu.ma Added my error description. – Raj Jun 16 '20 at 15:32
  • 1
    Well you'd start by deserializing it to a `List`, because that's what your JSON appears to represent. You can then iterate over each string in the list and deserialize that to a `UserInfo`. – Jon Skeet Jun 16 '20 at 15:33
  • @JonSkeet Thanks for your quick comment. I would like to avoid performance bottle neck by avoiding deserializing in a foreach loop. No other way around? – Raj Jun 16 '20 at 15:34
  • 1
    Do you have any evidence that this *would* be a performance bottleneck? If it would be, are you able to serialize to a more sensible format to start with? (A list of strings where each string is JSON is pretty unfortunate.) – Jon Skeet Jun 16 '20 at 15:35
  • @JonSkeet I dont have evidence now. But we anticipate more data to be loaded in here. Also, i read through and found out DeSerialization is a CPU bound and thereby would like to save infra cost too – Raj Jun 16 '20 at 15:38
  • to check which correct format of your json please use this site https://app.quicktype.io/ it seems you try to parse string – Mina Fawzy Jun 16 '20 at 15:40
  • how did you get the jsoninput? You have a list of serialized objects instead of serialized list of objects so you need to loop to deserialize them or serialize in correct way – Adassko Jun 16 '20 at 15:40
  • @MinaFawzy i think json list is in correct format, hence i was able to deserialize one by one item in a foreach loop, as i updated in the question – Raj Jun 16 '20 at 15:42
  • @Adassko jsoninput is an output of another method that performs some busines logic and returns IEnumerable. Updated the same in question too. – Raj Jun 16 '20 at 15:43
  • @Raj: well, this another method must serialize objects in a loop and returns array of separately serialized object. It should return a single string if it would serialize a list of objects. To deserialize it you need to revert what was done in that another method - if it used loop then you will need to use loop as well – Adassko Jun 16 '20 at 15:48
  • @Adassko Thanks for your thoughts. The other method returns IEnumerable which is nothing but Dictionary.Where(x => x.Value == null).Select(x => x.Key).ToHashSet(). The values in Dictionary are -> Key is String, Value is UserInfo object serialized. So, in that case i should deserialize one by one? If not, i should serialize entire list in one shot? Am i right? – Raj Jun 16 '20 at 17:39

1 Answers1

2

Please look at this fiddle: https://dotnetfiddle.net/XpjuL4

This is the code:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;

//Below are my classes,
public class UsersInfo 
{
    public List<UserInfo> UserInfoList { get; set; }
    public UsersInfo()
    {
        UserInfoList = new List<UserInfo>();
    }
}

public class UserInfo
{
    public string Id { set; get; }
    public string Name { set; get; }
    public string LastName { set; get; }
    public string ProfilePictureUrl { set; get; }
    public string SmallUrl { set; get; }
    public string ThumbnailUrl { get; set; }
    public string Country { set; get; }
    public bool IsInvalid { set; get; }
}

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        Option1();
        Option2();
    }

    public static void Option1(){
        string json = @"{""UserInfoList"":[
            {""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
            { ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
        ]}";
        var obj = JsonConvert.DeserializeObject<UsersInfo>(json);
        obj.UserInfoList.ForEach(e => Console.WriteLine(e.Id));
    }

    public static void Option2(){
    string json = @"[
            {""id"":""11ef2c75 - 9a6d - 4cef - 8163 - 94daad4f8397"",""name"":""bracing"",""lastName"":""male"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false},
            { ""id"":""318c0885-2720-472c-ba9e-1d1e120bcf65"",""name"":""locomotives"",""lastName"":""riddles"",""profilePictureUrl"":null,""smallUrl"":null,""thumbnailUrl"":null,""country"":null,""isInvalid"":false}
        ]";
        var obj = JsonConvert.DeserializeObject<List<UserInfo>>(json);
        obj.ForEach(e => Console.WriteLine(e.Id));
    }
}

Both work, and are basically very close to what you are doing. You can either serialize it as a list (based on your json, I think that's the closest to your use case, and that's Option 2).

However, put extra attention to the JSON. I had to re-parse your JSON to make it work (https://jsonformatter.org/json-parser is a nice website to do it). For the sake of explaining the example, in C#, @ means raw string, and in raw string, quotes are escaped with double quotes "".

I would expect that the business logic generating this JSON is not correct, if the JSON you pasted is the direct result from it.

EDIT Given the OP's comment:

Thanks Tu.ma for your thoughts. The other method returns IEnumerable which is nothing but Dictionary.Where(x => x.Value == null).Select(x => x.Key).ToHashSet(). The values in Dictionary are -> Key is String, Value is UserInfo object serialized. So, in that case i should deserialize one by one? If not, i should serialize entire list in one shot? Am i right? – Raj 12 hours ago

The problem is in the way you are generating the list of UsersInfo. The result from Dictionary<string,string>.Where(x => x.Value == null).Select(x => x.Key).ToHashSet() is a bunch of strings, not of objects, so you need to serialize them one by one.

If you are worried about the linearity of the approach, you could consider running through it in parallel. Of course, you need to judge if it fits your application.

var userInfoStrings = Dictionary<string,string>.Where(x => x.Value == null).Select(x => x.Key).ToHashSet();

var UserInfoList = userInfoStrings.AsParallel().Select (u => JsonConvert.DeserializeObject<UsersInfo>(u)).ToList();
Tu.Ma.
  • 1,325
  • 10
  • 27
  • Thanks Tu.ma for your thoughts. The other method returns IEnumerable which is nothing but Dictionary.Where(x => x.Value == null).Select(x => x.Key).ToHashSet(). The values in Dictionary are -> Key is String, Value is UserInfo object serialized. So, in that case i should deserialize one by one? If not, i should serialize entire list in one shot? Am i right? – Raj Jun 16 '20 at 17:36
  • 1
    I see. The result from `Dictionary.Where(x => x.Value == null).Select(x => x.Key).ToHashSet()` is a list of strings, not of Users. So you need to serialize one by one. Please see the update in the answer. – Tu.Ma. Jun 17 '20 at 06:18
  • Thanks for the suggestions. Pretty much covered my expectation. Will consider AsParallel() method based on our app data and performance. – Raj Jun 17 '20 at 18:57