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.

Martin de Ruiter
  • 515
  • 1
  • 6
  • 25
  • What **exactly** do you mean by a "generic object"? If you mean something with ``, can't you simply tell us which objects are involved? If you mean something like `dynamic`, please say so. – Lasse V. Karlsen Jul 31 '19 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> Errors { get; } = new Dictionary>(); }` – Lasse V. Karlsen Jul 31 '19 at 16:20
  • I made some edits to clarify my question. – Martin de Ruiter Jul 31 '19 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: https://stackoverflow.com/questions/2546138/deserializing-json-data-to-c-sharp-using-json-net. Ignore the part of the question that sounds different from yours and look at the answers. – Scott Hannen Jul 31 '19 at 16:28
  • Did you try the class I provided in my comment above? You can deserialize into it with something like `JsonConvert.DeserializeObject(json)`. – Lasse V. Karlsen Jul 31 '19 at 16:47

4 Answers4

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);
gleng
  • 6,185
  • 4
  • 21
  • 35
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
  }
}
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 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 – Giox Oct 26 '22 at 22:33
1

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

var json = JsonConvert.DeserializeObject<dynamic>(originalJson);
German Casares
  • 309
  • 1
  • 10
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.

G.Dimov
  • 2,173
  • 3
  • 15
  • 40
  • I don't know which error fields I can expect beforehand. – Martin de Ruiter Jul 31 '19 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](http://json2csharp.com/) and deserialize that. – Scott Hannen Jul 31 '19 at 16:36