Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 25 days ago.
Improve this question
I have am consuming some survey data via JSON from an API for my .Net app. I have created a class from the JSON file in my .net app. The JSON has a node called Response[] which is an array - so my survey platform gives me back multiple surveys. This works great when I get two or more surveys back (as its an array).
var root = JsonConvert.DeserializeObject<SurveyJsonModel.Rootobject>(json);
However, if the survey platform only returns back one survey the deserialisation fails, I suspect as the JSON is not returning an array. See attached screen shot of my model that I have created from the JSON. Any idea how I resolve - so it works for one record as well as multiples? Also not fail for zero records eithier. I suspect my model needs chnaging or do I need to use a different deserialisation method
TIA
The error message I get is:
Please see below the error message:
Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'SurveyJsonModel+Response[]' because the type requires a JSON array(e.g. [1, 2, 3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1, 2, 3]) or change the deserialized type so that it is a normal .NET type (e.g.not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
This is my class that I am using - im not sure where I add the constructor
public class SurveyJsonModel
{
public class Rootobject
{
public Xml xml { get; set; }
public Responses Responses { get; set; }
}
public class Xml
{
public string version { get; set; }
}
public class Responses
{
public Response[] Response { get; set; }
}
public class Response
{
public string startDate { get; set; }
public string endDate { get; set; }
public string status { get; set; }
public string ipAddress { get; set; }
}
}
This is my JSON string that returns one result,if it returns two surveys my code worked - but the below fails for one record as its not an array
{"?xml":{"#version":"1.0"},"Responses":{"Response":{"startDate":"2023-01-26 10:13:16","endDate":"2023-01-26 10:13:29","status":"0","ipAddress":"192.168.0.1"}}}
You don't need any custom converters, in this case I usually recommend to create a very simple JsonConstructor. And I fixed some bugs in your classes
using Newtonsoft.Json;
var result = JsonConvert.DeserializeObject<Rootobject>(json);
public partial class Responses
{
public Response[] Response { get; set; }
[JsonConstructor]
public Responses(JToken Response)
{
if (Response.Type == JTokenType.Array)
this.Response = Response.ToObject<Response[]>();
else
this.Response = new Response[] { Response.ToObject<Response>() };
}
public Responses() { }
}
public class Rootobject
{
[JsonProperty("?xml")]
public Xml Xml { get; set; }
public Responses Responses { get; set; }
}
public class Xml
{
[JsonProperty("#version")]
public string Version { get; set; }
}
If you are using .NET Core 3 or higher you can try to change the type of the Response property to JsonElement and check the ValueKind property to see if it is an object or an array.
Related
This question already has answers here:
Deserializing JSON with dynamic keys
(4 answers)
Complicated Json to C# Object Deserialize with classes
(2 answers)
Using JSON.NET to read a dynamic property name
(1 answer)
Closed 10 months ago.
I'm having an issue with JSON that I'm getting back for a hotel booking API. Essentially I'm taking the output and trying to create a class so that I can put it into an object. The problem is this: The JSON is returning objects and we can't readily use this format to make a C# class because of how it's formatted:
Example of how the JSON is formatted
Here is a snippet of it. Attributes is the highest level, then "pets" is next. The values we need for this are id: 5058 and name: Service Animals are allowed, however they are creating this "5058" and "5059" and "2050" object which is making it difficult to create a class and properly deserialize it.
I'm fairly new at C# (formerly long-time C programmer), so trying to understand the best way to make a class for something like this where the "5058" is not actually created as a class ... I would prefer if we could ingest that level into an array or list perhaps?
This is what something like json2csharp.com outputs...
public class Pets
{
public _5058 _5058 { get; set; }
public _5059 _5059 { get; set; }
public _2050 _2050 { get; set; }
}
And then
public class _5059
{
public string id { get; set; }
public string name { get; set; }
}
5059 should not be a class... That appears to be the name of the object; I want to ignore that because the ID: in the object is 5059
This wont work since there are thousands of IDs, and we're not looking to create a separate class for each ID -
I would like to make a class more like this
public class Pets
{
public string id { get; set; }
public string name {get; set; }
}
This is how I'm receiving the JSON
{
"pets":{
"5058":{
"id":"5058",
"name":"Service animals are allowed"
},
"5059":{
"id":"5059",
"name":"Service animals are exempt from fees/restrictions"
},
...
}
}
(This is a small snippet)
Again, here, they have "5059":{"id":"5059","name":"Service animals...."
So, what's the best way to ingest this with a class in C# without creating classes for the ID, the way a JSON to C# class creator would do?
Thanks for you help
That looks like a Dictionary<string, Pet> where those 5058, 5059, etc. are the keys.
public class Data
{
public Dictionary<string, Pet> pets { get; set; }
}
public class Pet
{
public string id { get; set; }
public string name { get; set; }
}
Deserialize the json as below
var data = JsonSerializer.Deserialize<Data>(json);
or if you're using Newtonsoft.Json
var data = JsonConvert.DeserializeObject<Data>(json);
This is an old application (.Net 4.5).
I am following the guide here: https://weblog.west-wind.com/posts/2012/aug/30/using-jsonnet-for-dynamic-json-parsing
My goal is to have a way to store a flexible json structure without tying it down to a static structure. For example, in the TriggerJson below, the actual Trigger field is of type string, which is supposed to be json. That json structure could reflect ExpiryTriggerJson, or some other structure which is determined by TriggerType.
I have the following structure:
public class TriggerJson
{
public string TriggerType { get; set; }
public string ConfiguredBy { get; set; }
public string Trigger { get; set; }
}
public class ExpiryTriggerJson
{
public string ActionType { get; set; }
public TriggerRecipient[] Recipients { get; set; }
}
public class TriggerRecipient
{
public string Id { get; set; }
public string Name { get; set; }
public bool IsTag { get; set; }
}
In the following code, I am creating a list of TriggerJson such that each element's Trigger field be a json structure made from ExpiryTriggerJson object:
var tjList = new List<TriggerJson>();
var triggerJson = new TriggerJson();
triggerJson.TriggerType = TriggerJsonHelper.ExpiryTriggerType;
triggerJson.Trigger = JsonConvert.SerializeObject(new ExpiryTriggerJson
{
Recipients = taskRecipients,
ActionType = TriggerJsonHelper.ExpiryTriggerActionType_Task
});
triggerJson.ConfiguredBy = configuredBy;
tjList.Add(triggerJson);
fieldValue.TriggersJson = JsonConvert.SerializeObject(tjList);
This creates the following structure for example where Trigger field reflects a serialized structure which has escaped double quotes due to double serialization:
[{"TriggerType":"ExpiryTrigger","ConfiguredBy":"acd1ac353ac44e078aaef8ce6479a4c6","Trigger":"{\"ActionType\":\"CreateReminderTask\",\"Recipients\":[{\"Id\":\"70050a95-f31b-41b7-9b49-0688fa76dba5\",\"Name\":\"blah blah\",\"IsTag\":false}]}"}]
This creates a problem for me when trying to deserialize this data later on when reading it back:
JArray jsonObj = JArray.Parse(triggersJson);
foreach (dynamic obj in jsonObj)
{
if (obj.TriggerType == ExpiryTriggerType)
{
ExpiryTriggerJson triggerData = obj.Trigger.ToObject<ExpiryTriggerJson>();
The above code tries to parse back ExpiryTriggerJson structure that was first assigned to the field Trigger of TriggerJson element. This throws a runtime deserialization exception when executing the last line trying to convert to ExpiryTriggerJson which I suspect happens due to double deserialization.
My question is how do I accomplish my goal of storing static/structural json data as a string and then parse it back in a nested manner?
This might be what you want.
public dynamic Trigger {get;set;}
Then trigger will be resolved to whatever type it receives at runtime.
I am using an API that returns me the result JSON formatted like this:
{
"undefined":{
"theresult":{
"back_1s":{
"consumed":1115287.58,
"min_cons":28789,
"max_cons":1086498.58,
"totalobjs":12683,
"totalproces":4298
},
"back_10s":{
"consumed":1115287.58,
"min_cons":28789,
"max_cons":1086498.58,
"totalobjs":12683,
"totalproces":4298
}
}
}
}
The first thing I did was creating a C# object that has 5 properties for each of the JSON's values.
Then I de-serialized the JSON string into an array of this new object.
However I have no idea what back_1s is, and what it will represent in C#,not to mention theresult and the undefined.
I just see no way for me to de-serialize it without help.
This is how I de-serialize in C#
List<NEWOBJECT> gooddata = JsonConvert.DeserializeObject<List<NEWOBJECT>>(jsonstring);
EDIT #1:
I am getting this error when I deserialize in C#
Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'mvcAndrew.Controllers.NEWOBJECT[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Easiest ist to generate the C# Classes from JSON:
http://json2csharp.com/
If you deserialize it use the generated RootObject class (or rename the class) that should do the trick.
This will generate two classes for Back1s / Back10s - you can still use only one class (delete the other one) and edit the "Theresult" class corresponding (for example, I renamed Back1s to BackClass and deleted the Back10s class)
public class Theresult
{
public BackClass back_1s { get; set; }
public BackClass back_10s { get; set; }
}
You can also use Newtonsoft.json.
var files = JObject.Parse(YourJsonHere);
var recList = files.SelectToken("$..theresult").ToList();
foreach (JObject item in recList.Children())
{
string values = item["consumed"].ToString();
// You can get other values here
}
Need to create a class structure same as your return object may be kind of
public class backDetails
{
public double consumed { get; set; }
public double min_cons { get; set; }
public double max_cons { get; set; }
public double totalobjs { get; set; }
public double totalproces { get; set; }
}
public class TheResult
{
public backDetails back_1s { get; set; }
public backDetails back_10s { get; set; }
}
public class MyClass
{
public TheResult theresult { get; set; }
}
Then this will work
List<MyClass> gooddata = JsonConvert.DeserializeObject<List<MyClass>>(jsonstring);
I need to deserialize the following Json, which according to Jsonlint.com is valid, but ive not come across this before or cannot find examples of similar Json and how to deal with it?
[1,"Bellegrove / Sherwood ","76705","486","Bexleyheath Ctr",1354565507000]
My current system with like this:
Data class:
[DataContract]
public class TFLCollection
{ [DataMember(Name = "arrivals")]
public IEnumerable<TFLB> TFLB { get; set; }
}
[DataContract]
public class TFLB
{
[DataMember]
public string routeName { get; set; }
[DataMember]
public string destination { get; set; }
[DataMember]
public string estimatedWait { get; set; }
}
Deserializer:
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TFLCollection));
using (var stream = new MemoryStream(Encoding.Unicode.GetBytes(result)))
{ var buses = (TFLCollection)serializer.ReadObject(stream);
foreach (var bus in buses.TFLBuses)
{
StopFeed _item = new StopFeed();
_item.Route = bus.routeName;
_item.Direction = bus.destination;
_item.Time = bus.estimatedWait;
listBox1.Items.Add(_item);
My exsiting deserializer works with a full Json stream and iterates through it, but in my new Json I need to deserialize, it only have 1 item, so I wont need to iterate through it.
So is it possible to deserialize my Json example using a similar method than I currently do?
I would say that you are attempting to overcomplicate things. What you have is a perfectly formed json array of strings. If I were you I would deserialize that to an .net array first, and then write a 'mapper' function to copy the values across:
public TFLB BusRouteMapper(string[] input)
{
return new TFLB {
Route = input[x],
Direction = input[y],
};
}
And so on. Of course this assumes that you know what order your json is going to be in, but if you are attempting this in the first place then you must do!
I am having issues with understanding how to make this happen.
Basically we have an API, the user sends a JSON of the format:
{
"Profile":[
{
"Name":"Joe",
"Last":"Doe",
"Client":{
"ClientId":"1",
"Product":"Apple",
"Message":"Peter likes apples"
},
"Date":"2012-02-14"
}
]
}
I have a class called Profile with parameters Name, Last, and an object as one of its members called Client as well as property Date.
Something like this:
public class Profile {
public string Name {get; set;}
public string Last {get; set;}
public Client client {get; set;}
public DateTime dDate {get; set;}
}
So basically, I am not sure how to grab the JSON and then map it to my object.
Any help with "helping" me understand would be much appreciated.
You can use Json.NET to deserialize your json string as (with some modifications to your classes)
var yourObject = JsonConvert.DeserializeObject<Root>(jsonstring);
public class Root
{
public Profile[] Profile;
}
public class Profile
{
public string Name { get; set; }
public string Last { get; set; }
public Client Client { get; set; }
public DateTime Date { get; set; }
}
public class Client
{
public int ClientId;
public string Product;
public string Message;
}
You can use a JSON library for this, for example Newtonsoft.Json which is free. It will map json to your types automatically.
Sample:
public static T Deserialize<T>(string json)
{
Newtonsoft.Json.JsonSerializer s = new JsonSerializer();
return s.Deserialize<T>(new JsonTextReader(new StringReader(json)));
}
There is also a NuGet package available.
Easiest way I know is to use JSON.Net by newtonsoft.
To make it easier to understand, I always make matching classes in C# with the same name.
Then its easier to deserialize it.
As an example, if it is an array of objects in js, it will map to a list of object with the same names in C#.
As for the date time, its a bit tricky.
Id do the client side validation and Datetime.tryParse in the serverside, itll take care of the dashes or slashes.
var serializer = new JavaScriptSerializer();
List<abc> abcList = serializer.Deserialize<List<abc>>(PassedInJsonString);
I know this is a long time question, but I would like to add one more option, which does not use third party libraries, and only uses stock .Net libraries, and is available from .Net Core 3.1 onwards.
First of all, I leave a link to the official Microsoft documentation (where you will find examples on how to serialize and deserialize json strings): https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to
Let's build on your example. We have our starting json string:
{
"Profile":[
{
"Name":"Joe",
"Last":"Doe",
"Client":{
"ClientId":"1",
"Product":"Apple",
"Message":"Peter likes apples"
},
"Date":"2012-02-14"
}
]
}
If we build a data structure that can hold that definition, it would be something like:
public class Root
{
public List<Profile> Profile { get; set; }
}
public class Profile
{
public string Name { get; set; }
public string Last { get; set; }
public Client Client { get; set; }
public string Date { get; set; }
}
public class Client
{
public string ClientId { get; set; }
public string Product { get; set; }
public string Message { get; set; }
}
Now, and finally the answer to how to deserialize a json string into a particular object without third party libraries:
Root root = JsonSerializer.Deserialize<Root>(json);
Where json is the variable that contains your json string.
I add another link of interest, the official documentation of the Deserialize(...) method: https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializer.deserialize
Something that is really useful is the exception that can be thrown, JsonException: https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonexception
DataContractJsonSerializer does the job, but it uses more sophisticated format for DateTime serialization.