Problems to deserialize JSON data to IDbSet<T> - c#

I have the following json data:
{
"Persons": [
{ "Person": { "FirstName":"A", "Surname": "B" } },
{ "Person": { "FirstName":"C", "Surname": "D" } },
{ "Person": { "FirstName":"E", "Surname": "F" } }
]
}
My class definitions are:
public class PersonContext
{
public IDbSet<Person> Persons { get; set; }
}
public class Person
{
public string FirstName { get; set; }
public string Surname { get; set; }
}
When I use fastJSON to deserialize it to an object, I receive a NullReferenceException.
PersonContext context = fastJSON.JSON.ToObject<PersonContext>(jsonText);
Debugging source code of fastJSON, the exception is thrown on CreateGenericList, because the col variable of the method after calling (IList)Reflection.Instance.FastCreateInstance(pt); is null. So after, when it tries to add the parsed dictionary, it raises the exception.
Can I configure serialization process to ensure that IDbSet<T> objects are correctly processed?
Thanks in advance.
PS: You can also clone my repo in github in order to reproduce this issue.

This is the answer for my question by mr. Mehdi Gholam (fastJSON owner) on this thread:
fastJSON needs concrete types and not interfaces to be defined so it knows what type to create.
So change your code to :
public class PersonContext
{
public List<Person> Persons { get; set; }
}

Related

How to create a .NET Core Serializer for indented Javascript objects

I am trying to serialize JSON objects received from an API in a cli app. I'm having issues understanding how to create the objects in .NET for JSON objects which have an indented structure.
For example, this is fine:
{"status": "ok" }
public class Success
{
public string status { get; set; }
}
But something like this is where I'm stuck and both of the examples from the below return null when the client API receives them.
[
{
"id": "some_uuid_string_1",
"message": "hello"
},
{
"id": "some_uuid_string_2",
"message": "world"
}
]
Attempted solution
public class Received
{
public Dictionary<string,string> received { get; set; }
}
Alternatively I also tried a simpler structure, leaving out the explicit names and just using the IDs and values, which is closer to what my app requires and lets me make smaller requests.
{
"some_uuid_string_1": "hello",
"some_uuid_string_2": "world"
}
For this example I tried this, a list of key value pairs in the form of a dictionary.
public class Message
{
public Dictionary<string,string> message { get; set; }
}
public class Received
{
public List<Message> received { get; set; }
}
How can I create objects in C# for these two structures? One indented with set names and one 'generic' with no set names.
public class MyClass
{
public string id { get; set; }
public string message { get; set; }
}
[
{
"id": "some_uuid_string",
"message": "hello"
},
{
"id": "some_uuid_string",
"message": "world"
}
]
Deserializes to a List<MyClass> or MyClass[]
{
"some_uuid_string_1": "hello",
"some_uuid_string_2": "world"
}
Deserializes to
public class MyClass
{
public string some_uuid_string_1 { get; set; }
public string some_uuid_string_2 { get; set; }
}
or Dictionary<string, string>
The reason your Received class solution didn't work is because it is expecting a JSON property of received, as your class has a property named received, but the JSON does not.
This is the same issue with your Message class. Your class has property message whereas your JSON does not.
create a class
public class MessageId
{
public string id { get; set; }
public string message { get; set; }
}
you can deserialize your json
using Newtonsoft.Json;
var messages=JsonConvert.DeserializeObject<List<MessageId>>(yourJson);

Cannot deserialize the current JSON array when returned value can be either array or single item

I am new to Newtonsoft.Json so please excuse my ignorance - however I am coming up against this issue when trying to Deserialize the following Json to either a c# object or indeed manually.
The Json is
{
"travellerInfo": [
{
"passengerData": {
"travellerInformation": {
"passenger": [
{
"type": "ADT",
"firstName": "MARY MRS"
},
{
"type": "INF",
"firstName": "JOSHUA"
}
],
"traveller": {
"surname": "SMITH",
"quantity": "2"
}
}
}
},
{
"passengerData": {
"travellerInformation": {
"passenger": {
"type": "ADT",
"firstName": "JOHN MR"
},
"traveller": {
"surname": "SMITH",
"quantity": "1"
}
}
}
}
]
}
So as you can see, on the first 'passenger' item, this returns as an Array, however on the second 'passenger' item, it doesn't return as an array, just a single block. I am not in control of the Json being sent to me - it comes from an external system. My C# classes are
public class Passenger
{
public string type { get; set; }
public string firstName { get; set; }
}
public class Traveller
{
public string surname { get; set; }
public string quantity { get; set; }
}
public class TravellerInformation
{
public List<Passenger> passenger { get; set; }
public Traveller traveller { get; set; }
}
public class PassengerData
{
public TravellerInformation travellerInformation { get; set; }
}
public class TravellerInfo
{
public PassengerData passengerData { get; set; }
}
and I call
var example = JsonConvert.DeserializeObject<TravellerInfo>(jsonString);
I am getting the error
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Script1.TravellerInfo' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'travellerInfo', line 57, position 20.
I tried putting a [JsonArray] attribute on the Passenger class to force it to deserialise as an array/list, but same error occured as I think the underlying item is a JProperty instead of a JObject.
So how can I get this to work when the ["passenger"] can come back as both an Array and Single object ?
Cheers in Advance
You can try deserialize it as dynamic and then do some checks to types. Check if it is IEnumerable.
That should do the job.
Try this. Replace List<Passenger> with object passenger in TravellerInformation:
public class Traveller
{
public string surname { get; set; }
public string quantity { get; set; }
}
public class TravellerInformation
{
public object passenger { get; set; }
public Traveller traveller { get; set; }
}
public class PassengerData
{
public TravellerInformation travellerInformation { get; set; }
}
public class TravellerInfo
{
public PassengerData passengerData { get; set; }
}
And call this by passing List<TravellerInfo> instead of TravellerInfo:
var example = JsonConvert.DeserializeObject<List<TravellerInfo>>(jsonString);
Also for these cases you can use this service which automatically creates C# classes from JSON objects, so you don't have to worry about correctness.

C# - Newtonsoft : Generic class for Client Response

After hours of attempts and research, I am asking for your help.
I am calling a public API which returns the same structure except for the datas returned.
For examples, the REST calls which retrieve stations and districts return those two JSON answers :
Stations response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : {
"station": [{
"number": "stationId",
"name": "stationName",
"address": "stationAddress",
"state": "1",
"latitude": "stationLat",
"longitude": "stationLong",
"slotsavailable": "10",
"bikesavailable": "20",
"pos": "0",
"district": "stationDistrict",
"lastupdate": "2016-03-28T11:47:08+02:00"
}, {...}, ...]}
}
Districts response :
"response" : {
"status": { "#attributes": {"code": "0", "message": "OK"} },
"data" : { "district": [{"id": "districtId", "name": "districtName"}, {...}, ...] }
}
I am using a .NET 4.5/C# solution with Newtonsoft.Json to execute the call.
I want to make the object, mapped to the client response, generic so the execution of the call will be made as follow :
var result = await client.Execute<Response<ApiResponseDistrict>>(request);
var result = await client.Execute<Response<ApiResponseStation>>(request);
My first attempt was to make a non generic call (create a full object by returned datas) which was a success.
My second attempt was to created a generic object so I made the following classes using the JsonProperty of the library Newtonsoft :
public class ApiResponse<T>
{
[JsonProperty("response")]
public Response<T> Response { get; set; }
}
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
public class ApiResponseDistrict
{
[JsonProperty("district")]
public List<District> Districts { get; set; }
}
public class District
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
At this point, when I am executing the call the object Response is valorized and also its property Status with the value waited but the property Data is never valorized (null).
My third attempt was to continue on the second attempt but using the JsonObject of the Newtonsoft library which it's given (with the same result) :
[JsonObject("district")]
public class ApiResponseDistrict
{
public List<District> Districts { get; set; }
}
As I am new to Newtonsoft, I would like to know if it is possible to use generic classes, as I am trying to do, to mapped the object returned by the call or I have to create a complete object for each "data" returned ?
Thank you for your answer and explanations or clues for me to find the answer !
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public Data<T> Data { get; set; }
}
public class Data<T>
{
public T ResponseData { get; set; }
}
This adds another layer between the data, so a response would look like this:
{
"Status": …,
"Data": {
"ResponseData": {
<The actual type T>
}
}
}
Instead, you want to remove that ResponseData level:
public class Response<T>
{
[JsonProperty("status")]
public Status Status { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
}
So for example, for the JSON above, you would have a StationResponseData class:
public class StationResponseData
{
public List<Station> Stations
{ get; set; }
}
And then you would deserialize the JSON as Response<StationResponseData>. The Station class would then contain those properties for number, name, address, etc.

How to displayJson Object Name/Label while returning the list of the same object type

Here are my Class
[DataContract(Name="Test")]
public class Test
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Type { get; set; }
}
[DataContract(Name="Root")]
public static class Root
{
[DataMember(Name="TestList")]
public static List<Test> TestList { get; set; }
}
Expected Json To be returned
{
"Test":[
{
"Name": "MyApp",
"Type": "web"
},
{
"Name": "MyDatabase",
"Type": "db"
}
]
}
Actual Json Returned
[
{
"Name": "MyApp",
"Type": "web"
},
{
"Name": "MyDatabase",
"Type": "db"
}
]
WebApi Method to return the objects
[HttpGet]
public IEnumerable<Test> Get()
{
return Root.TestList;
}
The problem i am facing is when i run the above code I see the json data being returned in the "Actual" Format but i would love to see the Json in the "Expected Format" (please see above for the formats). The only difference is the label of the array. How can i put this label? i looked at tons of json docs but no luck. Please help.
Your method is returning a List<Test> so that will be serialized as a JSON array. If you want to see a JSON object with a named array-valued property, you need to return a POCO containing an appropriately named property, such as your Root:
[HttpGet]
public Root Get()
{
return Root;
}
Also, you need to change the name from TestList to Test:
[DataContract(Name="Root")]
public class Root
{
[DataMember(Name="Test")] // Changed this
public List<Test> TestList { get; set; }
}
Or, if your Root contains other properties you don't want serialized, or in other ways can't be serialized (because it's static), you can always return some generic wrapper, like so:
[DataContract]
public class RootWrapper<T>
{
[DataMember(Name = "Test")]
public T Test { get; set; }
}
And then
[HttpGet]
public RootWrapper<IEnumerable<Test>> Get()
{
return new RootWrapper<IEnumerable<Test>> { Test = Root.TestList };
}

Json.NET JsonConvert.DeserializeObject() return null value

i tried to Deserialize this string :
string _jsonObject = {\"Ad\":{\"Type\":\"Request"\,
\"IdAd\":\"xxx#xxx.com\",
\"Category\":\"cat\",
\"SubCategory\":\"subcat\"},
\"Position\":{\"Latitude\":\"38.255\",
\"Longitude\":\"1.2\",
\"Imei\":\"0123456789\"};
}";
Message _message = JsonConvert.DeserializeObject<Message>(_jsonObject);
Works pretty for "Ad" but not instanciate "Position".
Any idea ?
I forgot to make the properties public. Don't forget to do that...
In the interest of helping others that may be experiencing this issue, or one related to it...
In my case, I had an object with an array of other objects, and one of the reference-type properties on those sub-objects was always null after deserialization. I tried all kinds of things, including downloading the JSON.Net source and stepping through it to find the failure point.
To make a long story short, the problem was, of course, my own. Here is a highly simplified version of my JSON and classes.
JSON
{
"$id": "1",
"RowCount": 10,
"Rows": [{
"$id": 2",
"ItemId": "1",
"ItemName": "Some Item",
"Owner": {
"Name": "John Doe",
"Id": "711D04F5-586F-4FD4-8369-4C00B51DD86F",
// other properties...
},
"OwnerId": "711D04F5-586F-4FD4-8369-4C00B51DD86F"
},
// more rows
]
}
Classes
public class Items
{
public int RowCount { get; set; }
public IEnumerable<Item> Rows { get; set; }
}
public class Item
{
private string ownerId;
public string ItemId { get; set; }
public string ItemName { get; set; }
public Person Owner { get; set; }
public string OwnerId
{
get { return this.ownerId; }
set {
if (value != this.ownerId)
{
this.Owner = null;
}
this.ownerId = value;
}
}
}
public class Person
{
public string Name { get; set; }
public string Id { get; set; }
// other properties
}
What was happening is that, because the Owner property appeared in the JSON prior to the OwnerId property, when the OwnerId property was set, the setter code determined that the current value was not the same as the value being set (since the current value was null), so it set the Owner property to null.
To fix it I also check the value being set against the id of the Owner object as well, and skip setting Owner to null if they are the same.
Admittedly, the cause of my problem may not be the same for everyone, but this is at least a cautionary tale to double-check what is happening when your objects are being initialized during deserialization.
I don't know how you are trying to deserialize, but this should work....
string json = "{\"Ad\":{\"Type\":\"Request\", \"IdAd\":\"xxx#xxx.com\", \"Category\":\"cat\", \"SubCategory\":\"subcat\"},\"Position\":{\"Latitude\":\"38.255\", \"Longitude\":\"1.2\", \"Imei\":\"0123456789\"}}";
var obj = JsonConvert.DeserializeObject<RootObject>(json);
public class Ad
{
public string Type { get; set; }
public string IdAd { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
public class Position
{
public string Latitude { get; set; }
public string Longitude { get; set; }
public string Imei { get; set; }
}
public class RootObject
{
public Ad Ad { get; set; }
public Position Position { get; set; }
}
In my case, my class properties had internal setters and after setting them public the problem solved.
In my case there is a more subtle error. It is easy to add leading or trailing spaces in the json keys by mistake. When that happens, the key is not recognized and attempting to deserialize it sets the value to null.
For example: {" id": 123}
This id field is not recognized because of the leading space " id". To fix it, fix the json to have instead "id".
Make sure the name of array in JSON matches with property name in your class
Illustrating (Look for "Components"):
JSON:
{
"Components": [
{
"Attribute1": "ABC",
"Attribute2": "XYZ"
}
]
}
Class:
public class MyClass
{
public IList<Component> Components { get; set; }
}
Deserialize:
JsonConvert.DeserializeObject<MyClass>(File.ReadAllText(#"ComponentSet.json"))
My problem was that I was including the class name at the beginning of my JSON string. I had copy-pasted from the serialized output of another class that contained the one I wanted to deserialize and I had purposefully included the class name thinking this was the correct JSON string. Once I removed the class name from my JSON string, it deserialized just fine.
This article was helpful in realizing this: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/4d766a28-ff38-477f-8abf-48ed01f74cd2/jsonconvertdeserializeobjectlttgtjsonstring-returning-all-propertieslttgt-as-null?forum=wpdevelop
I did not see this answer here so I am including it hoping that it helps those who made the same silly mistake as me.
I've never had any issues using Newtonsoft.Json, but decided to go with built in json libraries in latest project. Ended up with null result. Turns out the following will fail:
JSON:
{
"myProperty": "abc"
}
CLASS:
public void MyClass
{
public string MyProperty { get; set; }
}
Why does it fail? "myProperty" in json is camel case (starts with lower case letter), while MyProperty in MyClass starts with upper case letter. If you make both cases the same it works. I tried figuring out how to configure case insensitivity for the entire app, but apparently that's not possible to do, so I went back to Newtonsoft.JSON and the problem went away.
In my case, it was because I did not have a public constructor on my class.
This is what my class originally looked like:
public class TreeGroup
{
public string Name { get; set; }
public SiteGroup Group { get; set; }
public List<TreeMimicObject> Children { get; set; }
public TreeGroup(SiteGroup item)
{
// Notice this constructor takes a SiteGroup object and there
// is no default constructor
}
}
so I changed the class from the above to this:
public class TreeGroup
{
public string Name { get; set; }
public SiteGroup Group { get; set; }
public List<TreeMimicObject> Children { get; set; }
public TreeGroup()
{
// Added this default constructor here!!
}
public TreeGroup(SiteGroup item)
{
// ...
}
}
and it worked!
In my case the problem was deserializeobject return null when try to convert null value from json to int.
public class ItemCalcResModel
{
public int cartId;
}
I solved the problem by enable nullable in project:
#nullable enable
public class ItemCalcResModel
{
public int? cartId;
}

Categories

Resources