0

I have the following JSON (I can't change the incoming JSON as it is from a 3rd party system):

{
  "id": 23,
  "userName":"[email protected]",
  "tags":
  {
     "Employee ID":
     {
        "name":"Employee ID",
        "value":"123456789"
     },
     "Job Family":
     {
       "name": "Job Family",
       "value": "Accounting and Finance"
     }
  }
}

First, I tried to deserialize using this class structure:

public class User
{

    [JsonProperty("id")]
    public int ID { get; set; }
    [JsonProperty("username")]
    public string Email { get; set; }
    [JsonProperty("tags")]
    public TagsJson Tags { get; set; }
}

public class TagsJson
{
    [JsonProperty("tags")]
    public List<Tag> Tags { get; set; }
}

public class Tag
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("value")]
    public string Value { get; set; }
}

In using Newtonsoft's JsonConvert.DeserializeObject(json);, the User.Tags property is always empty. This is obviously because there are no "Tags" under the "Tags" attribute.

Yet, if I change the User class as follows...

public class User
{

    [JsonProperty("id")]
    public int ID { get; set; }
    [JsonProperty("email")]
    public string Email { get; set; }
    [JsonProperty("tags")]
    public List<Tag> Tags { get; set; }
    // I even tried Tag[] instead of List<Tag> here
}

...I get the following error:

Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Tag]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

Any suggestions on creating the User class to allow it to deserialize correctly would be greatly appreciated.


EDIT

So this may or may not be the best answer, but it works. The tags coming in will be one of a dozen different names. So I created a Tags class with a property for each of the 12 possibilites. Since none are required, any of them that do appear will get populated. Here's my adjusted User, Tags (formerly TagsJson) and Tag classes below - but I'm definitely interested in a better solution.

public class User
{

    [JsonProperty("id")]
    public int ID { get; set; }
    [JsonProperty("username")]
    public string Email { get; set; }
    [JsonProperty("tags")]
    public Tags AllTags { get; set; }
}

public class Tags
{
    [JsonProperty("Employee ID")]
    public Tag EmployeeID { get; set; }
    [JsonProperty("Job Family")]
    public Tag JobFamily { get; set; }        
    // ... and 10 more properties for additional tags that may appear but are not required
}

public class Tag 
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("value")]
    public string Value { get; set; }
}

The suggested answer of this question does not work in my case because the JSON is not an array or a collection but a list of unique attribute names with a name/value pairing.

3
  • tags in the example is a single object. if it was an array it would have been wrapped in [] Commented May 17, 2017 at 21:08
  • Possible duplicate of How to deserialize json string to object list in c# dot Commented May 18, 2017 at 0:09
  • @Zinov both questions are about json deserialization, the answer to the question is pretty trivial and there is already enough info on stackoverflow to solve it. However this question is specifically about deserializing a specific schema, which is not the same as the schema of the data in the question you've linked. Commented May 18, 2017 at 4:34

3 Answers 3

0

Well using the Visual Studio paste Json as classes yields...

public class Rootobject
{
    public int id { get; set; }
    public string userName { get; set; }
    public Tags tags { get; set; }
}

public class Tags
{
    [JsonProperty(PropertyName = "Employee ID")]
    public EmployeeID EmployeeID { get; set; }

    [JsonProperty(PropertyName = "Job Family")]
    public JobFamily JobFamily { get; set; }
}

public class EmployeeID
{
    public string name { get; set; }
    public string value { get; set; }
}

public class JobFamily
{
    public string name { get; set; }
    public string value { get; set; }
}

I had to add in the JsonProperty attributes myself. However I think a better solution would be...

public class Rootobject2
{
    public int id { get; set; }
    public string userName { get; set; }
    public IDictionary<string, NameValuePair> tags { get; set; }
}
public class NameValuePair
{
    public string name { get; set; }
    public string value { get; set; }
}

Although the paste Json as classes was a good starting point to easily copy and paste the code into the favoured solution.

Some test code...

string json = Resource1.String1;

Rootobject test = JsonConvert.DeserializeObject<Rootobject>(json);

Rootobject2 test2 = JsonConvert.DeserializeObject<Rootobject2>(json);
Sign up to request clarification or add additional context in comments.

1 Comment

This answer worked quite well - and the link showing how to paste JSON into a class was very useful. I put this into my code and all is working. I marked this as the solution and gave it a +1 (it doesn't show up because I'm still too new on this site). Thanks for your help!
0

Not sure your JSON is correct but why is there space in your property name Employee ID or Job Family. Fix those in Tags class and we are good to go.

public class EmployeeID
{
    public string name { get; set; }
    public string value { get; set; }
}

public class JobFamily
{
    public string name { get; set; }
    public string value { get; set; }
}

public class Tags
{
    public EmployeeID __invalid_name__Employee ID { get; set; }
    public JobFamily __invalid_name__Job Family { get; set; }
}

public class User
{
    public int id { get; set; }
    public string userName { get; set; }
    public Tags tags { get; set; }
}

This is what i got from json2csharp.com

3 Comments

I did the same - got the same results - the "invalid name" part seems to imply that the JSON is invalid?
@motor75: You need to confirm this JSON from its source.
Changing the property names is not required. The "invalid name" thing is because you can't have property names with spaces in C#, but you can in Javascript. The name is not invalid - it's just that C# is not as expressive. Try using [JsonProperty("Employee ID")] public string EmployeeId { get; set; } or similar
0

Your JSON shows that your tags object is an Object - not an Array. You cannot deserialize an Object into a C# List because they are different structures.

If the keys in tags are dynamic/changing, then perhaps try

[JsonProperty("tags")]
Dictionary<string, string> Tags { get; set; }

Edit

It appears that your JSON is not well-formed; if you aren't able to modify it, you might have to use a custom JsonConverter.

2 Comments

I'm thinking that is the solution - except I'm getting this error: Additional information: Unexpected character encountered while parsing value: {. Path 'tags['Employee ID']', line 1, position 835 It appears "Employee ID" needs to have the space removed?
Well, I removed the space (added an underscore) and that didn't see to fix it: Unexpected character encountered while parsing value: {. Path 'tags.Employee_ID', line 1, position 835.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.