Mike Mike - 3 months ago 19
JSON Question

SingleValueArrayConverter of an array returning null properties

I'm trying to use a custom singlearrayconverter to access the values of my json array, but I keep getting null values, I'm wondering where I could be doing something wrong.

I have the following JSON:

{
"message": "success",
"action": "user_info",
"data": {
"profile_info": {
"querying": "0",
"tps": {
"1": {
"profile_url": "anotherfakeurl",
"file_hash": "hash",
"icon_path": "",
"time_of_insertion": "0000-00-00 00:00:00",
"tp_id": "1",
"user_id": "4",
"tp_user_id": "1377839182243200",
"last_use": "0000-00-00 00:00:00",
"active": "0",
"user_display": "it's a me",
"selected": "1",
"prof_pic": "fakeurl"
}
}
}
}
}


And I have the following datamodel:

[JsonProperty("tps")]
[JsonConverter(typeof(SingleValueArrayConverter<Tps>))]
public List<Tps> TpsList { get; set; }


And I'm using this converter:

public class SingleValueArrayConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}



public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object retVal = new Object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T>() { instance };
}
else if (reader.TokenType == JsonToken.StartArray)
{
retVal = serializer.Deserialize(reader, objectType);
}
return retVal;
}

public override bool CanConvert(Type objectType)
{
return false;
}
}


And every other value is correct, it even gives me the right array count. But the contents of each Tps property are either empty or null.

Thank you,

edit: Here is the full Data Model.

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class UserInfo
{
[JsonProperty("message")]
public string Message { get; set; }

[JsonProperty("action")]
public string Action { get; set; }

[JsonProperty("data")]
public Data Data { get; set; }
}


public class Data
{

[JsonProperty("profile_info")]
public ProfileInformation ProfileInformation { get; set; }
}

public class ProfileInformation
{
[JsonProperty("querying")]
public string Querying { get; set; }

[JsonProperty("tps")]
[JsonConverter(typeof(SingleValueArrayConverter<Tps>))]
public List<Tps> TpsList { get; set; }
}

public class Tps
{
[JsonProperty("profile_url")]
public string ProfileUrl { get; set; }

[JsonProperty("file_hash")]
public string FileHash { get; set; }

[JsonProperty("icon_path")]
public string IconPath { get; set; }

[JsonIgnore]
[JsonProperty("time_of_insertion")]
public DateTime TimeOfInsertion { get; set; }

[JsonProperty("tp_id")]
public int TpId { get; set; }

[JsonProperty("user_id")]
public int UserId { get; set; }

[JsonProperty("tp_user_id")]
public long TpUserId { get; set; }

[JsonIgnore]
[JsonProperty("last_use")]
public DateTime LastUse { get; set; }

[JsonProperty("active")]
public string Active { get; set; }

[JsonProperty("user_display")]
public string UserDisplay { get; set; }

[JsonProperty("selected")]
public string Selected { get; set; }

[JsonProperty("prof_pic")]
public string ProfilePicture { get; set; }
}

Answer

I am not saying this is the most elegant or best way around, but it works. You can use a dictionary to achieve the desired bahavior. So, lose the converter, then move back and forth between a list and a dictionary, key being that TpId field it seems.

public class ProfileInformation
{
    [JsonProperty("querying")]
    public string Querying { get; set; }

    List<Tps> _tpsList = null;
    [JsonIgnore]        
    public List<Tps> TpsList {
        get {
            if (_tpsList == null && _tpsDict != null) {
                _tpsList = _tpsDict.Values.ToList();
            }                    
            return _tpsList; 
        }
        set { _tpsList = value; }
    }

    Dictionary<int, Tps> _tpsDict = null;
    [JsonProperty("tps")]
    public Dictionary<int, Tps> TpsDict { 
        get {
            if (_tpsDict == null && _tpsList != null) {
                _tpsDict = _tpsList.ToDictionary(x => x.TpId);
            }
            return _tpsDict;
        }
        set { _tpsDict = value; }
    }
}

Test

var userInfo = new UserInfo() {
            Action = "user_info",
            Message = "success",
            Data = new Data() {
                ProfileInformation = new ProfileInformation() {
                    Querying = "0",
                    TpsList = new List<Tps>() {
                        new Tps() {
                            Active="0",
                            FileHash = "hash",
                            IconPath="",
                            LastUse= DateTime.MinValue,
                            ProfileUrl = "anotherfakeurl",
                            ProfilePicture = "fakeurl",
                           Selected = "1",
                           TimeOfInsertion = DateTime.MinValue,
                           TpId = 1,
                           TpUserId = 1377839182243200L,
                           UserDisplay = "it's a me",
                           UserId = 4
                        } } } } };

    string json = JsonConvert.SerializeObject(userInfo, Formatting.Indented);
    var newUserInfo = JsonConvert.DeserializeObject<UserInfo> (json);
    Assert.AreEqual(newUserInfo.Data.ProfileInformation.TpsList.Count,1);
    Assert.AreEqual(newUserInfo.Data.ProfileInformation.TpsDict.Count,1);