C# WebApi POST creating a objects with complex json data - c#

I have two models, a SettingCollection, and a SettingValue. A SettingCollection has many SettingValues. This is the setup of this relationship.
public class SettingCollection
{
public int SettingCollectionId { get; set; }
public string Name { get; set; }
public string Key { get; set; }
public int Priority { get; set; }
public ICollection<SettingValue> SettingValues {get; set; }
}
and
public class SettingValue
{
public int SettingValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public int SettingCollectionId { get; set; }
public SettingCollection SettingCollection { get; set; }
}
To create a new SettingCollection and SettingValues in one call, I am POSTing the following payload:
{
"Name": "Company Collection",
"Key": "company_collection",
"Priority": 3,
"SettingValues":
[{"Name": "Is this true", "Value": "True"}]
}
And my response is:
System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)
Is this just something I cannot do and will have to use NewtonSoft to suss out the raw data in the controller?
Thanks!

Add this options to your newtonsoft.json in your startup file
AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
})

These classes are self referenced, so they go into the loop. You can just ignore sub classes with JsonIgnoreAttribute. I used this with System.Text.Json.JsonSerializer and works fine.
public class SettingValue
{
public int SettingValueId { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public int SettingCollectionId { get; set; }
[JsonIgnore]
public SettingCollection SettingCollection { get; set; }
}

Related

Custom C# object from JSON

I get the following JSON response.
[
{
"Issue": {
"ID": 80,
"Name": "Cold",
"Accuracy": 90,
"Icd": "J00",
"IcdName": "Acute nasopharyngitis [common cold]",
"ProfName": "Common cold",
"Ranking": 1
},
"Specialisation": [
{
"ID": 15,
"Name": "General practice",
"SpecialistID": 0
}
]
}
]
I tried to follow the instructions given here. But I can't seem to fit that solution here. And in the documentation is explained only the scenario where you already have the class predefined. Any help?
Presumptions
Your question is not even clear. What are you asking? I presume you are asking how to make a C# class from that JSON?
Solution
Firstly, the JSON is an array (if its top-level tags are [] its an array itself. If its top level is {} then its a single object.
So what you have is an array returned with one result inside of it.
Going to json2csharp and pasting your code gives this:
public class Issue
{
public int ID { get; set; }
public string Name { get; set; }
public int Accuracy { get; set; }
public string Icd { get; set; }
public string IcdName { get; set; }
public string ProfName { get; set; }
public int Ranking { get; set; }
}
public class Specialisation
{
public int ID { get; set; }
public string Name { get; set; }
public int SpecialistID { get; set; }
}
public class RootObject
{
public Issue Issue { get; set; }
public List<Specialisation> Specialisation { get; set; }
}
And you can see its created a RootObject almost indicating it is a single object, but you will need to deserialize this as a List<RootObject> not just RootObject.
So in C# that would be var result = JsonConvert.DeserializeObject<List<RootObject>>(theJsonString);
You should have a strongly typed c# class ready for your Json Response to be deserialized into... Json Utils has a generator to use, it came up with this:
public class Issue
{
[JsonProperty("ID")]
public int ID { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Accuracy")]
public int Accuracy { get; set; }
[JsonProperty("Icd")]
public string Icd { get; set; }
[JsonProperty("IcdName")]
public string IcdName { get; set; }
[JsonProperty("ProfName")]
public string ProfName { get; set; }
[JsonProperty("Ranking")]
public int Ranking { get; set; }
}
public class Specialisation
{
[JsonProperty("ID")]
public int ID { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("SpecialistID")]
public int SpecialistID { get; set; }
}
public class RootObject
{
[JsonProperty("Issue")]
public Issue Issue { get; set; }
[JsonProperty("Specialisation")]
public IList<Specialisation> Specialisation { get; set; }
}
Then use
RootObject jsonAsCSharpClass = JsonConvert.DeserializeObject<RootObject>(jsonResponse);
I'm not 100% sure this class is good for you though, i have never some across a response where the root response is an array, without defining a root property first, see how it starts with "[" instead of { ??? You may want to also try
List<RootObject> jsonAsCSharpClass = JsonConvert.DeserializeObject<List<RootObject>>(jsonResponse);
Or wait for someone with more knowledge on the subject to come along...

C# Parsing JSON String

I have tried countless methods to Parse my JSON string (Steam Public Data), yet nothing seems to work. I just want to be able to extract values from the string. For Example, obtaining the value of personaname which would return SlothGod. I have JSON.NET installed in my project.
Here is my JSON:
{
"response": {
"players": [
{
"steamid": "76561198301407459",
"communityvisibilitystate": 3,
"profilestate": 1,
"personaname": "SlothGod",
"lastlogoff": 1508389707,
"commentpermission": 1,
"profileurl": "http://steamcommunity.com/id/sleuthgud/",
"avatar": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/09/09cea52b91136fb3306c57771a746db2823b91ba.jpg",
"avatarmedium": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/09/09cea52b91136fb3306c57771a746db2823b91ba_medium.jpg",
"avatarfull": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/09/09cea52b91136fb3306c57771a746db2823b91ba_full.jpg",
"personastate": 0,
"realname": "Josh",
"primaryclanid": "103582791460168790",
"timecreated": 1462086929,
"personastateflags": 0,
"loccountrycode": "AU",
"locstatecode": "QLD"
}
]
}
}
Main method suggested to me:
public class Details
{
public string personaname { get; set; }
}
private void GetSteamDetails()
{
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Details>(SteamDetailsJson);
SteamName = data.personaname;
}
This is placed before Page_Load(). I then call GetSteamDetails(); when I want to fetch the name.
After my question being down voted, I decided to not give up on this problem. After extensive research, trial and error, and YouTube tutorials which are the most helpful IMO. I found that the data was containing a JSON array, and yes I will admit, I was confused with this, but the answer was to simply treat it like a C# array and add [1] to the end of players.
Details details = new Details();
public class Details
{
public string avatar { get; set; }
public string avatarmedium { get; set; }
public string avatarfull { get; set; }
public string realname { get; set; }
public string personaname { get; set; }
public string steamid { get; set; }
}
private void GetSteamDetails()
{
var SteamDetails= JsonConvert.DeserializeObject<dynamic>(SteamDetailsJson);
avatar = SteamDetails.response.players[1].avatar.ToString();
personaname = SteamDetails.response.players[1].personaname.ToString();
}
Based on the JSON string you provided, you should have the following C# classes to support it, or to deserialize the JSON object values into: I used this link to generate the classes.
public class Player
{
public string steamid { get; set; }
public int communityvisibilitystate { get; set; }
public int profilestate { get; set; }
public string personaname { get; set; }
public int lastlogoff { get; set; }
public int commentpermission { get; set; }
public string profileurl { get; set; }
public string avatar { get; set; }
public string avatarmedium { get; set; }
public string avatarfull { get; set; }
public int personastate { get; set; }
public string realname { get; set; }
public string primaryclanid { get; set; }
public int timecreated { get; set; }
public int personastateflags { get; set; }
public string loccountrycode { get; set; }
public string locstatecode { get; set; }
}
public class Response
{
public List<Player> players { get; set; }
}
public class RootObject
{
public Response response { get; set; }
}
Then, using Newtonsoft.Json, you can deserialize the JSON object into your C# classes as follow:
JsonConvert.DeserializeObject<RootObject>("yourJsonString");
You mention that Newtonsoft.Json already referenced in the project.
Use class to represent json data structure, then you can easy deserialize it.
You can use only properties you need in the class.
public class Player
{
public string personaname { get; set; }
}
var player = Newtonsoft.Json.JsonConvert.DeserializeObject<Player>(jsonString);
// use player.personaname
For updates question create classes which represent your data structure
public class Team
{
public List<Player> players { get; set; }
}
public class Response
{
public Team response { get; set; }
}
You can use http://json2csharp.com/ to generate a class automatically from a JSON string.

Unable to deserialize JSON in c#

I am getting the below JSON in response from a REST API.
{
"data":{
"id":123,
"zoneid":"mydomain.com",
"parent_id":null,
"name":"jaz",
"content":"172.1 6.15.235",
"ttl":60,
"priority":null,
"type":"A",
"regions":[
"global"
],
"system_record":false,
"created_at":"2017-09-28T12:12:17Z",
"updated_at":"2017-09-28T12:12:17Z"
}
}
and trying to resolve using below code but that doesn't result in a correctly deserialized type.
var model = JsonConvert.DeserializeObject<ResponseModel>(response);
below is a class according the field I received in JSON response.
public class ResponseModel
{
public int id { get; set; }
public string zone_id { get; set; }
public int parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public int priority { get; set; }
public string type { get; set; }
public string[] regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
What is missing?
You're missing a wrapper class.
public class Wrapper
{
public ResponseModel data {get;set}
}
and then do:
var model = JsonConvert.DeserializeObject<Wrapper>(response).data;
to get the instance of your ResponseModel out the data property.
You can deduct this from your json:
{ "data":
{ "id":123, /*rest omitted */ }
}
The type that will receive this JSON needs to have a property named data. The suggested Wrapper class acts as that type.
According to json2csharp website, your model seems to be incorrect. Try this one :
public class ResponseModel
{
public int id { get; set; }
public string zoneid { get; set; }
public object parent_id { get; set; }
public string name { get; set; }
public string content { get; set; }
public int ttl { get; set; }
public object priority { get; set; }
public string type { get; set; }
public List<string> regions { get; set; }
public bool system_record { get; set; }
public DateTime created_at { get; set; }
public DateTime updated_at { get; set; }
}
public class RootObject
{
public ResponseModel data { get; set; }
}
Here a cool trick you can do in Visual Studio 2015-2017 where it generates the the correct class if you just copy the JSON (ctrl + c).
You need to create a new class in visual studio and once inside the class go to Edit menu -> Paste special -> paste JSON As Classes.
Steps to generate json class
This will generate the C# object for that json for you and save you all the hassle :)
Your model does not match your response - it matches the data property. Simply wrap another object round it
public class ResponseData
{
public ResponseModel Data {get; set; {
}
and then
var model = JsonConvert.DeserializeObject<ResponseData>(response);

API to Object (with array) in C#

I'm returning data from transportapi.com & loading it into an object, but the data within the json array isn't being included.
The json returned is:
{
"atcocode": "490012745J",
"smscode": "47889",
"request_time": "2016-11-11T22:10:42+00:00",
"departures": {
"55": [
{
"mode": "bus",
"line": "55",
"line_name": "55",
"direction": "Bakers Arms",
"operator": "TFL",
"date": null,
"expected_departure_date": "2016-11-11",
"aimed_departure_time": null,
"expected_departure_time": "22:19",
"best_departure_estimate": "22:19",
"source": "Countdown instant"
}
]
}
}
Controller code:
var source = "http://transportapi.com/v3/uk/bus/stop/490012745J/live.json?api_key=[key]&app_id=[appid]";
Uri sourceUri = new Uri(source);
System.Net.Http.HttpClient sourceClient = new System.Net.Http.HttpClient();
System.Net.Http.HttpResponseMessage sourceResponse = await sourceClient.GetAsync(sourceUri);
var sourceArray = await sourceResponse.Content.ReadAsStringAsync();
var selections = JsonConvert.DeserializeObject<RootObject>(sourceArray);
Model class:
public class BusDepartures
{
public string mode { get; set; }
public string line { get; set; }
public string line_name { get; set; }
public string direction { get; set; }
public string busoperator { get; set; }
public object date { get; set; }
public string expected_departure_date { get; set; }
public object aimed_departure_time { get; set; }
public string expected_departure_time { get; set; }
public string best_departure_estimate { get; set; }
public string source { get; set; }
}
public class Departures
{
// First attempt, use BusDepartures object.
//public List<BusDepartures> BusDepartures { get; set; }
// Second attempt (as "55" is an array), use array, then convert to object later.
public string[] routes { get; set; }
}
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public Departures departures { get; set; }
}
Within the Departures class I did try and create a BusDepartures object to store the details of the departures, but I wondered whether, as it is an array, I should use the routes array instead? However when stepping through the code, the BusDepartures object (when it was uncommented) and the routes array were both null.
Any ideas? What am I missing?
Update:
Thanks to botond.botos for the answer. I amended my class to
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public IDictionary<int, IEnumerable<BusDepartures>> departures { get; set; }
}
and it worked.
You won't need the Departures class, and try to change the RootObject class the following way:
public class RootObject
{
public string atcocode { get; set; }
public string smscode { get; set; }
public string request_time { get; set; }
public IDictionary<int, IEnumerable<BusDepartures>> departures { get; set; }
}
I'm pretty sure your trying to map the property name "55" to a non-existent c# property. Either modify the json (which i'm assuming you can't) or use a more generic property to handle the departures.
I'm thinking maybe something like a generic Dictionary(Of int, List(of Departure)) .... which is of course vb and I'm going to guess at new Dictionary<#int, List>() in c# ? :)
public class departures {
public Dictionary<int, List<Departure>> BusDepartures {get; set; }
}

Access Elements in JSON File Using C#

I have an JSON result like this
{
"authenticationResultCode":"ValidCredentials",
"brandLogoUri":"http:\/\/dev.virtualearth.net\/Branding\/logo_powered_by.png",
"copyright":"Copyright © 2011 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.",
"resourceSets":[
{
"estimatedTotal":1,
"resources":[
{
"__type":"Location:http:\/\/schemas.microsoft.com\/search\/local\/ws\/rest\/v1",
"bbox":[
47.636257744012461,
-122.13735364288299,
47.643983179153814,
-122.12206713944467
],
"name":"1 Microsoft Way, Redmond, WA 98052",
"point":{
"type":"Point",
"coordinates":[
47.640120461583138,
-122.12971039116383
]
},
"address":{
"addressLine":"1 Microsoft Way",
"adminDistrict":"WA",
"adminDistrict2":"King Co.",
"countryRegion":"United States",
"formattedAddress":"1 Microsoft Way, Redmond, WA 98052",
"locality":"Redmond",
"postalCode":"98052"
},
"confidence":"High",
"entityType":"Address",
"geocodePoints":[
{
"type":"Point",
"coordinates":[
47.640120461583138,
-122.12971039116383
],
"calculationMethod":"InterpolationOffset",
"usageTypes":[
"Display"
]
},
{
"type":"Point",
"coordinates":[
47.640144601464272,
-122.12976671755314
],
"calculationMethod":"Interpolation",
"usageTypes":[
"Route"
]
}
],
"matchCodes":[
"Good"
]
}
]
}
],
"statusCode":200,
"statusDescription":"OK",
"traceId":"b0b1286504404eafa7e7dad3e749d570"
}
I want to get a list of objects, and every object will contain the value of coordinates
So how can access these element by name?
I am using C# as a code behind.
You can use package like Json.NET for this task.
and easily you can generate classes by giving json string from http://json2csharp.com/
then you can access properties of items as below
RootObject obj = JsonConvert.DeserializeObject<RootObject>(jsonText);
below are the classes generated from the json2csharp for given json
public class Point
{
public string type { get; set; }
public List<double> coordinates { get; set; }
}
public class Address
{
public string addressLine { get; set; }
public string adminDistrict { get; set; }
public string adminDistrict2 { get; set; }
public string countryRegion { get; set; }
public string formattedAddress { get; set; }
public string locality { get; set; }
public string postalCode { get; set; }
}
public class GeocodePoint
{
public string type { get; set; }
public List<double> coordinates { get; set; }
public string calculationMethod { get; set; }
public List<string> usageTypes { get; set; }
}
public class Resource
{
public string __type { get; set; }
public List<double> bbox { get; set; }
public string name { get; set; }
public Point point { get; set; }
public Address address { get; set; }
public string confidence { get; set; }
public string entityType { get; set; }
public List<GeocodePoint> geocodePoints { get; set; }
public List<string> matchCodes { get; set; }
}
public class ResourceSet
{
public int estimatedTotal { get; set; }
public List<Resource> resources { get; set; }
}
public class RootObject
{
public string authenticationResultCode { get; set; }
public string brandLogoUri { get; set; }
public string copyright { get; set; }
public List<ResourceSet> resourceSets { get; set; }
public int statusCode { get; set; }
public string statusDescription { get; set; }
public string traceId { get; set; }
}
Since you already appear to be using DataContractJsonSerializer, let's stick with that. The best way to deserialize json is to first define a model which will capture the relevant data e.g.
public class JsonModel
{
public int StatusCode { get; set; }
public string StatusDescription { get; set; }
public string TraceId { get; set; }
...
}
Next, decorate the model so it's fit for deserialization
[DataContract]
public class JsonModel
{
[DataMember(Name = "statusCode")]
public int StatusCode { get; set; }
[DataMember(Name = "statusDescription")]
public string StatusDescription { get; set; }
[DataMember(Name = "traceId")]
public string TraceId { get; set; }
...
}
Then finally, perform the deserialization
using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(jsonData)))
{
var serializer = new DataContractJsonSerializer(typeof(JsonModel));
var model = (JsonModel) serializer.ReadObject(memoryStream);
Console.WriteLine(model.StatusCode);
}
So how can access these element by name?
The other option for deserialization which would give you the ability to reference the properties by name would be to use a dynamic object e.g.
var model = new JavaScriptSerializer().Deserialize<dynamic>(jsonData);
Console.WriteLine(model["statusCode"]);
Add the classes for all Bing Maps REST Services from the URL below to your project:
JSON Data Contracts
Then, make sure that you add the using directive:
using BingMapsRESTService.Common.JSON;
and read the string as follows (where stream is a stream for your json):
var d = new DataContractJsonSerializer(typeof(Response));
var o = d.ReadObject(stream);

Categories