serializing a class in c# - c#

I was hoping someone could help me with a problem serialzing data into a class please?
I need to send the following json string to a webservice:
{ "arrivalAt": "2012-12-24T20:00:00.0000000Z", "pickup":{"streetName":"Amaliegade","houseNumber":"36","zipCode":"1256","city":"Copenhagen K","country":"DK","lat":55.68,"lng":12.59}, "dropoff":{"streetName":"Amaliegade","houseNumber":"36","zipCode":"1256","city":"Copenhagen K","country":"DK","lat":55.68,"lng":12.59}, "vehicleType": "fourSeaterAny", "comments": "Hello" }'
I put this json string into http://json2csharp.com/ and it generated the following class:
public class Pickup
{
public string streetName { get; set; }
public string houseNumber { get; set; }
public string zipCode { get; set; }
public string city { get; set; }
public string country { get; set; }
public double lat { get; set; }
public double lng { get; set; }
}
public class Dropoff
{
public string streetName { get; set; }
public string houseNumber { get; set; }
public string zipCode { get; set; }
public string city { get; set; }
public string country { get; set; }
public double lat { get; set; }
public double lng { get; set; }
}
public class RootObject
{
public string arrivalAt { get; set; }
public Pickup pickup { get; set; }
public Dropoff dropoff { get; set; }
public string vehicleType { get; set; }
public string comments { get; set; }
}
I have managed to do this before but have never had a situation where is there is a class within a class, so to speak. Meaning the "Pickup" & "DropOff" settings...
I am stuck when i try to work out what to do at this line...
Booking bookingdetails = new ClickATaxi_Classes.Booking(THIS IS WHERE I WILL PUT THE 17 BITS OF INFORMATION BUT HOW?);
I get the feeling there is something i need to do to the class to make it accept arguments but i have no idea where to start and how to send the pickup and dropoff information
can anyone help please?
thanks

First you should refactor that generated code a little bit
public class Location
{
public string streetName { get; set; }
public string houseNumber { get; set; }
public string zipCode { get; set; }
public string city { get; set; }
public string country { get; set; }
public double lat { get; set; }
public double lng { get; set; }
}
public class Booking
{
public string arrivalAt { get; set; }
public Location pickup { get; set; }
public Location dropoff { get; set; }
public string vehicleType { get; set; }
public string comments { get; set; }
}
There is no need for two classes that mean the same thing. After that you will just instantiate the booking object.
Booking obj = new Booking { arrivalAt = "ARRIVAL", pickup = new Location { streetName = "", houseNumber = "" ... }, dropoff = new Location { streetName = "", houseNumber = "" ...}, vehicleType = "", comments = "" }
Next you will serialize to a string, I like JSON.NET but you can use any serializer.
If you want to use JSON.NET you can install it via Nuget by following these instructions, next add the using statement to the top of your class that will serialize the object:
using Newtonsoft.Json;
Finally just call JsonConvert
string json = JsonConvert.SerializeObject(product);
Here are some links to other serializers:
http://msdn.microsoft.com/en-us/library/bb410770.aspx
http://www.servicestack.net/docs/text-serializers/json-csv-jsv-serializers
http://code.google.com/p/protobuf-net/

Json.NET. You need a JSON serializer. Just pick one that you like. The 3 that have been listed work great. And make sure you read this article to better understand why you need a JSON serializer.

Related

Json.NET Deserialize Property Without Deserializing Parent Object Above It

I am trying to take this JSON:
{
"title":"string",
"description":"string",
"date":"2021-04-19T01:05:38.000Z",
"image":"url",
"images":[
"url1",
"url2"
],
"attributes":{
"phonebrand":"x",
"phonecarrier":"y",
"forsaleby":"z",
"price":12345,
"location":"daLocation",
"type":"OFFERED"
},
"url":"url to listing"
}
And convert it into this C# Object:
public class Listing {
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("date")]
public DateTime? Date { get; set; }
[JsonProperty("image")]
public string Image { get; set; }
[JsonProperty("images")]
public string[] Images { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("price")]
public decimal Price { get; set; }
[JsonProperty("locationId")]
public int LocationId { get; set; }
[JsonProperty("categoryId")]
public int CategoryId { get; set; }
[JsonProperty("sortByName")]
public string SortByName { get; set; }
[JsonProperty("q")]
public string Q { get; set; }
[JsonProperty("location")]
public string Location { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("forsaleby")]
public string ForSaleBy { get; set; }
[JsonProperty("fulfillment")]
public string Fulfillment { get; set; }
[JsonProperty("payment")]
public string Payment { get; set; }
[JsonProperty("phonebrand")]
public string? PhoneBrand { get; set; }
[JsonProperty("phonecarrier")]
public string? PhoneCarrier { get; set; }
}
My problem is, I'm trying to deserialize properties like price and phonebrand but those properties are under an object in the JSON. So when I try to deserialize them like this, those properties can't be found and are set as null. How can I deserialize those properties without changing my C# Class to include an Attributes class? I want to do this because I think that it is a cleaner/better design compared the JSON I'm taking in.
I suggest two approaches that are very explicit and easy to follow for the next developer looking at the code.
Two classes
creating a intermediate dto class that is used for deserialisation and then creating the business logic object from that intermediate object.
var withAttributes = Deserialise<ListingDto>();
var flatObject = new Listing(withAttributes);
One class
You could provide accessors at the top level which dip into the subclasses.
public class Listing
{
public AttributesDto Attributes {get; set}
...
public string Url => Attributes.Url; // Maybe '?.Url'
}

JSON Deserializer returning NULL Values

I am trying to consume a REST API via a C# Console Application and I've got as far as getting the webservice to return the JSON file, with the format:
{"status":200,"result":{"postcode":"SW1W0DT","quality":1,"eastings":528813,"northings":178953,"country":"England","nhs_ha":"London","longitude":-0.145828,"latitude":51.494853,"european_electoral_region":"London","primary_care_trust":"Westminster","region":"London","lsoa":"Westminster 023E","msoa":"Westminster 023","incode":"0DT","outcode":"SW1W","parliamentary_constituency":"Cities of London and Westminster","admin_district":"Westminster","parish":"Westminster, unparished area","admin_county":null,"admin_ward":"Warwick","ccg":"NHS Central London (Westminster)","nuts":"Westminster","codes":{"admin_district":"E09000033","admin_county":"E99999999","admin_ward":"E05000647","parish":"E43000236","parliamentary_constituency":"E14000639","ccg":"E38000031","nuts":"UKI32"}}}
I have created a class AddressInfo which is as follows:
public class AddressInfo {
public string postcode { get; set; }
public int quality { get; set; }
public int eastings { get; set; }
public int northings { get; set; }
public string country { get; set; }
public string nhs_ha { get; set; }
public string admin_county { get; set; }
public string admin_district { get; set; }
public string admin_ward { get; set; }
public double longitude { get; set; }
public double latitude { get; set; }
public string parliamentary_constituency { get; set; }
public string european_electoral_region { get; set; }
public string primary_care_trust { get; set; }
public string region { get; set; }
public string parish { get; set; }
public string lsoa { get; set; }
public string msoa { get; set; }
public string ccg { get; set; }
public string nuts { get; set; }
public object codes { get; set; }
}
The code to call the API and get the values is:
string strJSON = string.Empty;
strJSON = rClient.makeRequest();
Console.Write(strJSON);
AddressInfo AI = new AddressInfo();
AI = Newtonsoft.Json.JsonConvert.DeserializeObject<AddressInfo>(strJSON);
However, when I debug, AI is returning the values as "NULL".
Thanks
Notice that your JSON has a nested structure. The AddressInfo is contained within its result property, it isn't at the top level.
Your actual class structure to deserialize the entire JSON response should look something like this (I've called the class JsonResponse but you can name it whatever you want):
class JsonResponse{
public int status { get; set; }
public AddressInfo result { get; set; }
}
Then deserialize it like this:
JsonResponse res = JsonConvert.DeserializeObject<JsonResponse>(strJSON);
AddressInfo addressInfo = res.result;
You're missing the fact that you need an outer class that has the properties int status and AdressInfo result.
You don't need to create a separate class to deserialize the entire response, this can be done dynamically to achieve desired result:
var source = "(your JSON");
dynamic data = JObject.Parse(source);
var d = JsonConvert.SerializeObject(data.result);
AddressInfo account = JsonConvert.DeserializeObject<AddressInfo>(d);
Your JSON is nested. The result is a nested object. That's why you are experiencing this issue.

Parse JSON Object / Array of Strings into new Custom Class

I'm trying to parse some JSON data and ultimatley store it in a database.
I'm having issues when storing a collection of strings / values which are not objects themselves.
For example - The "callingCodes" & "altSpellings"
I want to store these in an SQL table which will have reference to the country they belong to.
This is an example of the JSON:
{
"name":"Puerto Rico",
"topLevelDomain":[
".pr"
],
"alpha2Code":"PR",
"alpha3Code":"PRI",
"callingCodes":[
"1787",
"1939"
],
"capital":"San Juan",
"altSpellings":[
"PR",
"Commonwealth of Puerto Rico",
"Estado Libre Asociado de Puerto Rico"
],
"region":"Americas",
"subregion":"Caribbean",
"population":3474182,
"latlng":[
18.25,
-66.5
]
},
I originally created some C# classes to represent the data using http://json2csharp.com/
This sugguested I store the values as a list of strings, which I did:
public List<string> CallingCodes { get; set; }
I now want to store the data in a table, so I created a class "TopLevelDomain" to store / link the data to the parent country:
public class CallingCode
{
public int ID { get; set; }
public int CountryID { get; set; }
public string Code{ get; set; }
}
So I altered the parent to be as follows:
public ICollection<CallingCode> CallingCodes { get; set; }
Is it possible to direct the string values into the "Code" property of my new class?
Or am I trying to crowbar two pieces of logic into one?
Is the correct way to have models for the JSON, and manually restructure these into my new DB / Entity Framework Models?
This is the auto-generated class you get from such JSON. The tricky bit here is List of primitive types.
public class RootObject
{
public string name { get; set; }
public List<string> topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public List<string> callingCodes { get; set; }
public string capital { get; set; }
public List<string> altSpellings { get; set; }
public string region { get; set; }
public string subregion { get; set; }
public int population { get; set; }
public List<double> latlng { get; set; }
}
Certain databases like PostgreSQL supports array as primitive type. If you are using PostgreSQL then you can perhaps make those properties array of primitive type and store them on server as is.
For other databases which does not support array, you cannot store a list of primitive values into single column of database. The easiest way to deal with it is to introduce serialization and create single string which can be stored to server. So looking at above class, for public List<string> topLevelDomain property, you can rewrite it in following way,
[NotMapped]
public List<string> topLevelDomain
{
get => Deserialize(TopLevelDomainString);
set => TopLevelDomainString = Serialize(value);
}
public string TopLevelDomainString { get; set; }
With NotMapped attribute EF will not map topLevelDomain property. But TopLevelDomainString will be persisted to database and it will get values from topLevelDomain. As for Serialize/Deserialize methods, you can use any serialization method. You can use JsonSerializer directly (since you are already using JSON objects. Or you can just combine strings using , as delimiter and split string from server using it.
Starting with EF Core 2.1 version, you can use Value-Conversion feature directly to provide funcs to do conversion (essentially serialization code like above) to EF and EF will do it while reading/saving data from/to server. This will avoid you having to create additional CLR property.
Here is your auto-generated class:
public class RootObject
{
public string name { get; set; }
public List<string> topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public List<string> callingCodes { get; set; }
public string capital { get; set; }
public List<string> altSpellings { get; set; }
public string region { get; set; }
public string subregion { get; set; }
public int population { get; set; }
public List<double> latlng { get; set; }
}
Let's prepare another simple one:
public class MyRootObject
{
public MyRootObject(RootObject root)
{
Name = root.name;
List<CallingCode> callingCodesConverted = new List<CallingCode>();
foreach (string code in root.callingCodes)
{
CallingCode newCode = new CallingCode() { Code = code };
callingCodesConverted.Add(newCode);
}
CallingCodes = callingCodesConverted;
}
public string Name { get; set; }
public List<CallingCode> CallingCodes { get; set; }
}
Now you could first do encoding from json to class RootObject, and then create MyRootObject based on it:
string path = #"D:\test.txt";
var r = new StreamReader(path);
var myJson = r.ReadToEnd();
RootObject root = Json.Decode<RootObject>(myJson);
MyRootObject myroot = new MyRootObject(root);
Sure MyRootObject is only an example.
Is the correct way to have models for the JSON, and manually
restructure these into my new DB / Entity Framework Models?
Well some might use that in their code and some might do even worse than that. But, I personally like to use models/dtos for the things I could and know about the data.
am I trying to crowbar two pieces of logic into one?
Yes. But, it depends. Either strongly type/define objects and all or just Ser/Deser everytime.
Your data is known (no unkown properties or anything, so why serialize and deserialize it everytime?)
Solution 1 : if you use the JSON as is to create a DB Entry
Entites
public class Country //assuming this is country data
{
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("alpha2Code")]
public string Alpha2Code { get; set; }
[JsonProperty("alpha3Code")]
public string Alpha3Code { get; set; }
[JsonProperty("capital")]
public string Capital { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("subregion")]
public string Subregion { get; set; }
[JsonProperty("population")]
public long Population { get; set; }
[JsonProperty("topLevelDomain")]
public virtual List<TopLevelDomain> TopLevelDomains { get; set; }
[JsonProperty("callingCodes")]
public virtual List<CallingCodes> CallingCodes { get; set; }
[JsonProperty("altSpellings")]
public virtual List<AltSpellings> AltSpellings { get; set; }
[JsonProperty("latlng")]
public virtual List<Coordinates> Coordinates { get; set; }
}
public class TopLevelDomain
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string DomainName { get; set; }
}
public class CallingCodes
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string Code { get; set;} // either store it as String
//OR
public long Code { get; set;}
}
public class AltSpellings
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public string AltSpelling { get; set; }
}
public class Coordinates
{
public int Id { get; set; }
[ForeignKey("Country")]
public int CountryId {get; set; }
public virtual Country Country { get; set; }
public double Coordinates { get; set; } //again either as string or double, your wish. I would use double
}
Use it like so
//assuming using Newtonsoft
var myJson = ....assuming one Country;
var myJsonList = ...assuming List<Country>;
var country = JsonConvert.DeserializeObject<Country>(myJson);
var countries = JsonConvert.DeserializeObject<List<Country>>(myJson);
Solution 2 : First one can cause too many tables for a little data but First solution is a little more object based and typed, so Here is another one
Entity
public class Country //assuming this is country data
{
public int Id { get; set; }
public string Name { get; set; }
public string Alpha2Code { get; set; }
public string Alpha3Code { get; set; }
public string Capital { get; set; }
public string Region { get; set; }
public string Subregion { get; set; }
public long Population { get; set; }
public string TopLevelDomains { get; set; }
public string CallingCodes { get; set;}
public string AltSpellings { get; set; }
public double Longitude { get; set;}
public double Latitude { get; set; }
}
Model
public class CountryJson
{
public int Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("alpha2Code")]
public string Alpha2Code { get; set; }
[JsonProperty("alpha3Code")]
public string Alpha3Code { get; set; }
[JsonProperty("capital")]
public string Capital { get; set; }
[JsonProperty("region")]
public string Region { get; set; }
[JsonProperty("subregion")]
public string Subregion { get; set; }
[JsonProperty("population")]
public long Population { get; set; }
[JsonProperty("topLevelDomain")]
public List<string> TopLevelDomains { get; set; }
[JsonProperty("callingCodes")]
public List<string> CallingCodes { get; set;}
[JsonProperty("altSpellings")]
public List<string> AltSpellings { get; set; }
[JsonProperty("latlng")]
public List<string> Latlng { get; set; }
}
Use it like so
//assuming using Newtonsoft
var myJson = ....assuming one Country;
var countryJson = JsonConvert.DeserializeObject<CountryJson>(myJson);
//Write a Mapper Or Manual Map like below
var countryEntity = new Country
{
Name = countryJson.Name,
...
TopLevelDomains = JsonConvert.Serialize(countryJson.TopLevelDomains),
CallingCodes = JsonConvert.Serialize(countryJson.CallingCodes),
...//same for all list (NOTE: YOU NEED TO DESERIALIZE IT WHEN YOU FETCH IT FROM DB
Longitude = countryJson.Latlng.ElementAt(0),//assuming 0 is longi, 1 is lat
Latitude = countryJson.Latlng.ElementAt(1)//you can do it like above as well as string if you want
}

Deserialize Json with minus in property name [duplicate]

This question already has answers here:
Parsing field name with a colon in JSON
(2 answers)
Closed 6 years ago.
I have a JSON return as below.
{
"id": 100,
"name": "employer 100",
"externalId": "100-100",
"networkId": 1000,
"address": {
"street-address": "1230 Main Street",
"locality": "Vancouver",
"postal-code": "V6B 5N2",
"region": "BC",
"country-name": "CA"
}
}
So I created class to deserialize the above json.
public class Employer
{
public int id { get; set; }
public string name { get; set; }
public string externalId { get; set; }
public int networkId { get; set; }
public Address address { get; set; }
}
public class Address
{
public string street_address { get; set; }
public string locality { get; set; }
public string postal_code { get; set; }
public string region { get; set; }
public string country_name { get; set; }
}
var response = _client.Execute(req);
return _jsonDeserializer.Deserialize <Employer> (response);
But I could not get street-address, postal-code and country-name from Json string. I think because of Json output keys contain ""-"" (As result of that I'm getting null).
So how could I resolve my issue ?
Use the DeserializeAs attribute on your properties:
[DeserializeAs(Name = "postal-code")]
public string postal_code { get; set; }
This allows you to set the same of the property in the json that maps to the property in your class, allowing the property to have a different name to the son.
https://github.com/restsharp/RestSharp/wiki/Deserialization
If you're using JSON.net, use attributes on your properties to specify the names that they should match up to:
public class Employer
{
public int id { get; set; }
public string name { get; set; }
public string externalId { get; set; }
public int networkId { get; set; }
public Address address { get; set; }
}
public class Address
{
[JsonProperty("street-address")]
public string street_address { get; set; }
public string locality { get; set; }
[JsonProperty("postal-code")]
public string postal_code { get; set; }
public string region { get; set; }
[JsonProperty("country-name")]
public string country_name { get; set; }
}

Deserializing this JSON response to C#

I have this specific JSON response that I am trying to deserialize without success. I am hoping someone can help me.
Here is the JSON response I get:
{
"num_locations": 1,
"locations": {
"98765": {
"street1": "123 Fake Street",
"street2": "",
"city": "Lawrence",
"state": "Kansas",
"postal_code": "66044",
"s_status": "20",
"system_state": "Off"
}
}
}
I used json2csharp http://json2csharp.com and got these recommended classes:
public class __invalid_type__98765
{
public string street1 { get; set; }
public string street2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string s_status { get; set; }
public string system_state { get; set; }
}
public class Locations
{
public __invalid_type__98765 __invalid_name__98765 { get; set; }
}
public class RootObject
{
public int num_locations { get; set; }
public Locations locations { get; set; }
}
But when I try to use it in my code:
var locationResponse = JsonConvert.DeserializeObject<RootObject>(response.Content);
What I get is (Watch):
locationResponse : {RestSharpConsoleApplication.Program.RootObject} : RestSharpConsoleApplication.Program.RootObject
locations : {RestSharpConsoleApplication.Program.Locations} : RestSharpConsoleApplication.Program.Locations
__invalid_name__98765 : null : RestSharpConsoleApplication.Program.__invalid_type__98765
num_locations : 1 : int
Obviously I am not creating (json2csharp) the right classes for the DeserializeObject, and sadly I have no control over the JSON response (vendor = SimpliSafe).
It is obvious the "98765" is meant to be a value (location number) but json2csharp makes it into this __invalid_type__98765 class and this is probably why it gets null.
Any idea how should the classes look for this particular JSON to be successfully deserialized?
Thanks!
Zachs
You should be able to do this with a dictionary:
public class MyData{
[JsonProperty("locations")]
public Dictionary<string, Location> Locations {get;set;}
}
public class Location
{
public string street1 { get; set; }
public string street2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string s_status { get; set; }
public string system_state { get; set; }
}
Do you have a non-Express version of Visual Studio? If so, copy the JSON to clipboard and then go to the Visual Studio menu: Edit >> Paste special >> Paste JSON as classes.
Using that gives:
public class Rootobject {
public int num_locations { get; set; }
public Locations locations { get; set; }
}
public class Locations {
public _98765 _98765 { get; set; }
}
public class _98765 {
public string street1 { get; set; }
public string street2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string s_status { get; set; }
public string system_state { get; set; }
}
That suggests your JSON structure is not quite right.
You can also specify the property name via an attribute to use to get around this:
public class RootObject
{
public int num_locations { get; set; }
public Locations locations { get; set; }
}
public class Locations
{
[JsonProperty("98765")]
public LocationInner Inner { get; set; }
}
public class LocationInner
{
public string street1 { get; set; }
public string street2 { get; set; }
public string city { get; set; }
public string state { get; set; }
public string postal_code { get; set; }
public string s_status { get; set; }
public string system_state { get; set; }
}
...but it would really be better if the JSON were properly formatted such that the Locations was actually an array of location objects.

Categories