1

What is the best way to deserialize the following JSON response into a generic object? For example I would like to access the response message and a the list of errors (and accessing the field name and error message of it).

{
 "message": "The given data was invalid.",
 "errors": {
 "name": [
 "Name is required."
 ],
 "gender": [
 "Gender is required."
 ],
 "date_of_birth": [
 "Date of birth is required."
 ]
 }
}

Edit:

I would like to access the JSON object in a way something like this

string message = genericObject.message
foreach (error errorElement in genericObject.errors)
{
 string errorField = errorElement.fieldName;
 string errorDescription = errorElement.errorMessage;
}

Edit 2:

I don't know the possible error fields beforehand.

asked Jul 31, 2019 at 16:13
5
  • What exactly do you mean by a "generic object"? If you mean something with <T>, can't you simply tell us which objects are involved? If you mean something like dynamic, please say so. Commented Jul 31, 2019 at 16:19
  • 1
    I would create a proper class for that json, something like public class Response { public string Message { get; set; } public Dictionary<string, List<string>> Errors { get; } = new Dictionary<string, List<string>>(); } Commented Jul 31, 2019 at 16:20
  • I made some edits to clarify my question. Commented Jul 31, 2019 at 16:28
  • Words like "generic" and "dynamic" can confuse because they have very specific meaning. In this case you wouldn't need to create anything complex or generic or use dynamic. I think what you want is this: stackoverflow.com/questions/2546138/…. Ignore the part of the question that sounds different from yours and look at the answers. Commented Jul 31, 2019 at 16:28
  • Did you try the class I provided in my comment above? You can deserialize into it with something like JsonConvert.DeserializeObject<Response>(json). Commented Jul 31, 2019 at 16:47

4 Answers 4

2

Since you mention that you do not know which "error fields" will be present, a dictionary is the best way to go.

Here's a simple example:

void Main()
{
 string json = File.ReadAllText(@"d:\temp\test.json");
 var response = JsonConvert.DeserializeObject<Response>(json);
 response.Dump();
}
public class Response
{
 public string Message { get; set; }
 public Dictionary<string, List<string>> Errors { get; }
 = new Dictionary<string, List<string>>();
}

When executing this in LINQPad, I get this output:

sample LINQPad output

You can even add your own code from your question:

string json = File.ReadAllText(@"d:\temp\test.json");
var genericObject = JsonConvert.DeserializeObject<Response>(json);
string message = genericObject.Message;
foreach (var errorElement in genericObject.Errors) // see note about var below
{
 string errorField = errorElement.Key;
 string errorDescription = errorElement.Value.FirstOrDefault(); // see below
}

Note 1: The result of iterating a dictionary is a KeyValuePair<TKey, TValue>, in this case it would be a KeyValuePair<string, List<string>>.

Note 2: You've shown JSON having an array for each field, so errorElement.errorMessage isn't going to work properly since you may have multiple error messages.

You can nest some loops, however, to process them all:

string message = genericObject.Message;
foreach (var errorElement in genericObject.Errors) // see note about var below
{
 string errorField = errorElement.Key;
 foreach (string errorDescription in errorElement.Value)
 {
 // process errorField + errorDescription here
 }
}
answered Jul 31, 2019 at 16:54
1
  • I have a very similar issue, where the object is slightly different and I can't find the structure to use to deserialize: Metadata: [{propA: "81", propB: 50}] As you can see the values could also be different, not all strings. Field names are not known, as well as the number of them Commented Oct 26, 2022 at 22:33
2

There are many ways to do this.

The System.Web.Helpers assembly contains the Json class which you can do:

dynamic decodedObject = Json.Decode(json);

Another way would be to use the Newtonsoft.Json nuget package:

var deserializedObject = JsonConvert.DeserializeObject<dynamic>(json);
answered Jul 31, 2019 at 16:17
1

If you are willing to use Newtonsoft.Json you can use:

var json = JsonConvert.DeserializeObject<dynamic>(originalJson);
answered Jul 31, 2019 at 16:21
1

you would have to create the following classes:
RootObject.cs containing the following properties:

public class RootObject
{
 [JsonProperty("message")]
 public string Message { get; set; }
 [JsonProperty("errors")]
 public Errors Errors { get; set; }
}

Errors.cs, containing the following properties:

public class Errors
{
 [JsonProperty("name")]
 public string[] Name { get; set; }
 [JsonProperty("gender")]
 public string[] Gender { get; set; }
 [JsonProperty("date_of_birth")]
 public string[] DateOfBirth { get; set; }
}

And then you read the whole thing like this:

var inputObj = JsonConvert.DeserializeObject<RootObject>(json);

Where inputObj will be of type RootObject and json is the JSON you are receiving.

If you have implemented this correctly, use it like this:

var message = inputObj.Message;
var nameErrors = inputObj.Errors;
var firstNameError = inputObj.Errors.Name[0];

Here is a visual: Showing the whole object, filled with the properties: enter image description here

The "main" error: enter image description here

If you have any questions feel free to ask.

answered Jul 31, 2019 at 16:24
2
  • I don't know which error fields I can expect beforehand. Commented Jul 31, 2019 at 16:27
  • If that just means that fieldName might contain different values, I wouldn't use dynamic. I'd steer far away from that unless there's a very specific reason why you need it. If the data you're receiving is in a predictable structure and it's only the values that are changing (which is most of the time) then you can just define a class (or generate one using json2csharp and deserialize that. Commented Jul 31, 2019 at 16:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.