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.
4 Answers 4
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:
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
}
}
-
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 themGiox– Giox2022年10月26日 22:33:59 +00:00Commented Oct 26, 2022 at 22:33
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);
If you are willing to use Newtonsoft.Json you can use:
var json = JsonConvert.DeserializeObject<dynamic>(originalJson);
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.
-
I don't know which error fields I can expect beforehand.Martin de Ruiter– Martin de Ruiter2019年07月31日 16:27:38 +00:00Commented Jul 31, 2019 at 16:27
-
If that just means that
fieldName
might contain different values, I wouldn't usedynamic
. 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.Scott Hannen– Scott Hannen2019年07月31日 16:36:26 +00:00Commented Jul 31, 2019 at 16:36
<T>
, can't you simply tell us which objects are involved? If you mean something likedynamic
, please say so.public class Response { public string Message { get; set; } public Dictionary<string, List<string>> Errors { get; } = new Dictionary<string, List<string>>(); }
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.JsonConvert.DeserializeObject<Response>(json)
.