Martin de Ruiter
Martin de Ruiter

Reputation: 525

Deserialize dynamic json into generic .NET object

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.

Upvotes: 1

Views: 2908

Answers (4)

gleng
gleng

Reputation: 6304

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);

Upvotes: 2

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391724

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
  }
}

Upvotes: 2

G.Dimov
G.Dimov

Reputation: 2393

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.

Upvotes: 1

German Casares
German Casares

Reputation: 319

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

var json = JsonConvert.DeserializeObject<dynamic>(originalJson);

Upvotes: 1

Related Questions