-1

I have this json:

[{"trace":{"details":{"date":"[28-02-2016 11:04:26.856573]","type":"[info]","message":"[system done.]"},"context":{"context":[[{"ID":"john dillinger"}]]}}},{"trace":{"details":{"date":"[28-02-2016 11:04:26.856728]","type":"[info]","message":"[trace done.]"},"context":{"context":[[{"ID":"john dillinger"}]]}}}]

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type, because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.

I've created this class for deserialize it:

public class Testing
{
    public string date { get; set; }
    public string type { get; set; }
    public string message { get; set; }
    public string context { get; set; }
}

and this is the code for deserialize the content:

string responseText = "json above";
var obj = JsonConvert.DeserializeObject<Testing>(responseText); //on this line the problem

in the obj line I get the exception. I'm a bit rusty with c# so I don't know exactly what am I doing wrong. Someone could enlighten me?

Dillinger
  • 1,823
  • 4
  • 33
  • 78
  • Try `DeserializeObject`, add the array brackets, you're deserializing an array because the json is surrounded by `[...]`. And yeah, as others have pointed out, you're going to miss a lot of data here because of the hierarchical nature of your json and your flat class. – Lasse V. Karlsen Feb 28 '16 at 10:26

3 Answers3

3

Your json is not a flat data as your Testing class is. Try using following

public class Details
{
    public string date { get; set; }
    public string type { get; set; }
    public string message { get; set; }
}

public class Context
{
    public List<List<ContextElement>> context { get; set; }
}

public class Trace
{
    public Details details { get; set; }
    public Context context { get; set; }
}

public class RootObject
{
    public Trace trace { get; set; }
}

Just hit your json to http://json2csharp.com/ and it seems you need to add this type for the ID part of the context and modify the result so context uses this in the list.

public class ContextElement
{
    public string ID { get; set; }
}

Your parsed json is of format

json

Check this with https://jsonformatter.curiousconcept.com/ yourself. Then you just need to make a C# classes to match that structure.

Janne Matikainen
  • 5,061
  • 15
  • 21
  • just one thing: this generated line: `public List> context { get; set; }` is underlined in red: Unexpected use of an unbound generic name in `List<>` – Dillinger Feb 28 '16 at 10:27
  • Try List>, or actually you need some complex type to do that mapping. Seems a bit weird when you use https://jsonformatter.curiousconcept.com/ to intend the json, you have context inside the context which has array of an array of ID values? – Janne Matikainen Feb 28 '16 at 10:28
  • I used the tool for generate the class, put it in my code and try to get the object as: `var obj = JsonConvert.DeserializeObject(responseText);` but same error returned. What is wrong? – Dillinger Feb 28 '16 at 10:41
  • Guess the context is wrong in the json, where does this json come from? Has it been serialized properly? Because if the parser does not seem to understand it, there might be some problems. – Janne Matikainen Feb 28 '16 at 10:54
2

You need to deserialize a collection of Trace - like List<Trace>:

var obj = JsonConvert.DeserializeObject<List<Trace>>(responseText);

Assuming that you have the following DTOs:

public class Trace
{
    public TraceValue trace;
}

public class TraceValue
{
    public Details details;
    public Context context;
}

public class Details
{
    public String date;
    public String type;
    public String message;
}

public class Context
{
    public List<List<IdItem>> context;
}

public class IdItem
{
    public String ID;
}

Proof (response is just a line provided by you, but with escaped quotes, so that it can be put directly into the code):

var response = 
    "[{ \"trace\":{ \"details\":{ \"date\":\"[28-02-2016 11:04:26.856573]\",\"type\":\"[info]\",\"message\":\"[system done.]\"},\"context\":{ \"context\":[[{\"ID\":\"john dillinger\"}]]}}},{\"trace\":{\"details\":{\"date\":\"[28-02-2016 11:04:26.856728]\",\"type\":\"[info]\",\"message\":\"[trace done.]\"},\"context\":{\"context\":[[{\"ID\":\"john dillinger\"}]]}}}]";
var obj = JsonConvert.DeserializeObject<List<Trace>>(response);
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
  • I don't read the json from a file, this operation is executed by the API. The API return the json that you can see in my question, anyway I still get this error: `annot deserialize the current JSON array (e.g. [1,2,3]) into type 'API.Application.Transaction+Trace' because the type requires a JSON object` – Dillinger Feb 28 '16 at 11:27
  • @Dillinger Well, I don't know why it doesn't work for you. You can see in the edited answer, that the line is exactly the one you gave in your question. – Eugene Podskal Feb 28 '16 at 11:32
  • Wait, I missing to change the `obj` variable, now the error isn't displayed. How I can iterate through the `obj` with a foreach? – Dillinger Feb 28 '16 at 11:36
  • 1
    @Dillinger. As usual - `foreach (var traceObj in obj) { Console.WriteLine(traceObj.trace.context.context.First().First().ID); }` Though the data format is a bit convoluted, so getting any meaningful data will be a slightly frustrating task. – Eugene Podskal Feb 28 '16 at 11:39
  • The only problem is that you have defined a static context, the context is dynamic, let me show you an example, I could have a context like this: `"context":[[{"File":transactions_model.php","Linea":73,"ID":"john dillinger"}]]}}`. In you case I get only the ID but the File or some other content will missing... How I can fix this? – Dillinger Feb 28 '16 at 12:18
  • @Dillinger I have created DTOs according to the sample you have given. If you have any additional properties, then you should add them to the appropriate DTOs. Otherwise, if such fields are unknown even to you, then use http://stackoverflow.com/a/21763919/3745022 – Eugene Podskal Feb 28 '16 at 12:24
  • Could you please update the answer with the unknow fields? please. – Dillinger Feb 28 '16 at 12:50
  • @Dillinger You should add `public String File; public String Linea' to the `IdItem` class. And I am perfectly sure that you are quite capable of doing it on your own, if you are not one of [those guys](http://meta.stackoverflow.com/questions/258206/what-is-a-help-vampire). If it is so important to have such fields in the answer, then you can edit my answer and I will agree to that edit. – Eugene Podskal Feb 28 '16 at 13:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/104779/discussion-between-dillinger-and-eugene-podskal). – Dillinger Feb 28 '16 at 13:08
0

I think you should use JavaScripSerializer

JavaScriptSerializer jsSerializer = new JavaScriptSerializer();

you can try

var obj = jsSerializer.Deserialize<Testing>(responseText);

I am not sure about this solution, may be it will work or not in your case. But you can deserialize json string into string array of any dimension as:

var obj = jsSerializer.Deserialize<string[]>(responseText);
var obj = jsSerializer.Deserialize<string[][]>(responseText);
mmushtaq
  • 3,430
  • 7
  • 30
  • 47