C# model for nested properties - c#

I need to make API request to CloudFlare to purge cache of individual files.
Can someone please guide how to represent the below as C# model class.
files: [
"http://www.example.com/css/styles.css",
{
"url": "http://www.example.com/cat_picture.jpg",
"headers": {
"Origin": "cloudflare.com",
"CF-IPCountry": "US",
"CF-Device-Type": "desktop"
}
}
]

var obj = new
{
files = new object[]
{
"http://www.example.com/css/styles.css",
new
{
url = "http://www.example.com/cat_picture.jpg",
headers = new Dictionary<string,string>
{
{ "Origin", "cloudflare.com" },
{ "CF-IPCountry","US" },
{ "CF-Device-Type", "desktop"}
}
}
}
};
The dictionary is there because of the awkward property names like CF-IPCountry which make it not possible to use an anonymous type.
To show it working:
var json = Newtonsoft.Json.JsonConvert.SerializeObject(obj, Formatting.Indented);
gives:
{
"files": [
"http://www.example.com/css/styles.css",
{
"url": "http://www.example.com/cat_picture.jpg",
"headers": {
"Origin": "cloudflare.com",
"CF-IPCountry": "US",
"CF-Device-Type": "desktop"
}
}
]
}
Edit; that's not quite right - the dictionary didn't work, but I don't have time to fix it.

Using classes (maybe you could use better class names then mine :) ):
class Root
{
[JsonProperty(PropertyName = "files")]
public List<object> Files { get; set; } = new List<object>();
}
class UrlContainer
{
[JsonProperty(PropertyName = "url")]
public string Url { get; set; }
[JsonProperty(PropertyName = "headers")]
public Headers Headers { get; set; }
}
class Headers
{
public string Origin { get; set; }
[JsonProperty(PropertyName = "CF-IPCountry")]
public string CfIpCountry { get; set; }
[JsonProperty(PropertyName = "CF-Device-Type")]
public string CfDeviceType { get; set; }
}
Usage
var root = new Root();
// Add a simple url string
root.Files.Add("http://www.example.com/css/styles.css");
var urlContainer = new UrlContainer() {
Url = "http://www.example.com/cat_picture.jpg",
Headers = new Headers()
{
Origin = "cloudflare.com",
CfIpCountry = "US",
CfDeviceType = "desktop"
}
};
// Adding url with headers
root.Files.Add(urlContainer);
string json = JsonConvert.SerializeObject(root);
Note: I'm using Newtonsoft.Json

Related

Is there a better way to parse this JSON structure?

I'm dealing with a web service that defines the following JSON structure as the return for a GET to the 'positions' endpoint:
{
"positions": {
"position": [
{
"cost_basis": 207.01,
"date_acquired": "2018-08-08T14:41:11.405Z",
"id": 130089,
"quantity": 1.00000000,
"symbol": "AAPL"
},
{
"cost_basis": 1870.70,
"date_acquired": "2018-08-08T14:42:00.774Z",
"id": 130090,
"quantity": 1.00000000,
"symbol": "AMZN"
},
Which is all find and good, except that when there's just one position, they return:
{
"positions":
{
"cost_basis": 1870.70,
"date_acquired": "2018-08-08T14:42:00.774Z",
"id": 130090,
"quantity": 1.00000000,
"symbol": "AMZN"
}
}
Is there some industry trick to deserializing this from JSON? The best I've come up with is:
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"v1/accounts/{tradierHost.TradierAccount}/positions"))
using (HttpResponseMessage response = await this.tradierClient.SendAsync(httpRequestMessage))
{
// Make sure we executed with no errors.
response.EnsureSuccessStatusCode();
var jObject = JObject.Parse(await response.Content.ReadAsStringAsync());
IEnumerable<BrokerPosition> brokerPositions = null;
if (jObject["positions"] is JObject positionsObject)
{
// Update one position.
if (positionsObject["position"] is JObject positionObject)
{
var brokerPositionList = new List<BrokerPosition>();
brokerPositionList.Add(positionObject.ToObject<BrokerPosition>());
}
// Update many positions.
if (positionsObject["position"] is JArray positionArray)
{
brokerPositions = positionArray.ToObject<IEnumerable<BrokerPosition>>();
}
}
}
Is there a better way to parse this vendor's API? I don't see a practical way to use a POCO.
I prefer to use a constructor
Data data = JsonConvert.DeserializeObject<Data>(json);
classes
public class Data
{
public Positions Positions { get; set; } = new Positions();
[Newtonsoft.Json.JsonConstructor]
public Data(JToken positions)
{
var positionsObj = JObject.FromObject(positions);
if (positions["position"] != null)
Positions.Position = positionsObj["position"].ToObject<List<Position>>();
else
{
Positions.Position = new List<Position>();
Positions.Position.Add(positionsObj.ToObject<Position>());
}
}
}
public class Positions
{
public List<Position> Position { get; set; }
}
public class Position
{
public double cost_basis { get; set; }
public DateTime date_acquired { get; set; }
public int id { get; set; }
public double quantity { get; set; }
public string symbol { get; set; }
}
or if you don't need the whole object, it can be much simplier. You only need one class
var positionsObj = JObject.Parse(json)["positions"];
List<Position> positions = new List<Position>();
if (positionsObj["position"] != null)
positions = positionsObj["position"].ToObject<List<Position>>();
else
positions.Add(positionsObj.ToObject<Position>());
You can define your class model to use it to parse JSON in the model.And use System.Text.Json or Newtonsoft.Json
Like example:
var responseModel = JsonSerializer.Deserialize<YourReponseModel>(response.Content.ReadAsStringAsync());
So you can get access to Position by object property: responseModel.Positions

C# Newtonsoft.Json DeserializeObject if json contains an invalid token [duplicate]

This question already has answers here:
How can I use a reserved keyword as an identifier in my JSON model class?
(3 answers)
Closed 1 year ago.
How can i deserialize this json in C# using Newtonsoft.Json.JsonConvert.DeserializeObject?
The problem is that i cannot use "event" as a class property because its an invalid token.
{
"resultsPage": {
"results": {
"event": {
"location": {
"city": "London, UK",
"lng": -0.1150322,
"lat": 51.4650846
},
"uri": "http://www.....",
"displayName": "Test",
"id": 3037536,
"type": "Testtype",
"start": {
"time": "19:30:00",
"date": "2010-02-16",
"datetime": "2010-02-16T19:30:00+0000"
},
"status": "ok"
}
},
"status": "ok"
}
}
There's a few ways you could do this with Newtonsoft.
JsonConvert.DeserializeObject will return an object of type JObject, this can be done either by not specifying a type (instead casting after deserializing) or by specifying the JObject type.
From here you can access event because it is simply a key name, but you lose any strong typing of your json.
var jobj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(json);
var _event = jobj["resultsPage"]["results"]["event"];
Taking this a step further, you can use JsonConvert.DeserializeAnonymousType and specify the definition of your anonymous type, using #event or Event where event is present in the json. When accessing the property, you would need to use #event or Event depending on which you chose, and you gain the benefits of strongly typed objects.
var jobj = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(json, new {
resultsPage = new {
results = new {
#event = new {
location = new {
city = "",
lng = 0.0,
lat = 0.0
},
uri = "",
displayName = "",
id = 0,
type = "",
start = new {
time = "",
date = "",
datetime = new DateTime()
},
status = ""
}
},
status = ""
}
});
var _event = jobj.resultsPage.results.#event;
Next, you could create classes take this anonymous object definition and split it out into classes, again using #event or Event and it will deserialize.
var jobj = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonClass>(json);
var _event = jobj.resultsPage.results.#event;
public class JsonClass
{
public ResultsPage resultsPage { get; set; }
public string status { get; set; }
}
public class ResultsPage
{
public Results results { get; set; }
public string status { get; set; }
}
public class Results
{
public Event #event { get; set; }
}
public class Event
{
public Location location { get; set; }
...
}
public class Location
{
public string city { get; set; }
}
Or you could look at using a property attribute to map a completely different property name to the json key (the below is a modified excerpt of the above).
public class Results
{
[JsonProperty(PropertyName = "event")]
public EventResult EventResult { get; set; }
}
public class EventResult
{
public Location location { get; set; }
}

How to deserialise or format WebAPI result into specific json structure

I was working with a .net core 3.1 Web API. Which is getting data from an external API. Following is my code Controller part
[HttpGet("transinfo/{id}")]
public Object GettransactionData(int id)
{
var result=_transaction.GettransactionDetails(id).Result;
List<PipeLineResponse> P = JsonConvert.DeserializeObject<List<PipeLineResponse>>(result.ToString());
PipeLineResponseObject P1 = new PipeLineResponseObject();
P1.data = P;
return P1;
}
And my service code as follows
public async Task<Object> GettransactionDetails(int id)
{
string request=//fetched from db
var stringContent = new StringContent(request);
Client = utilities.GetHttpClient();
string apiEndpoint=//External API URL
HttpResponseMessage httpResponseMessage = await Client.PostAsync(apiEndpoint, stringContent);
if (httpResponseMessage.IsSuccessStatusCode)
{
return await httpResponseMessage.Content.ReadAsAsync<Object>();
}
}
But i am getting the result in following format (response from postman)
{
"data": [
{
"Tranid": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fields": {
"Fields.10": "1001",
"Fields.11": "Test1",
"Fields.12": "Fixed1"
}
},
{
"Tranid": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fields": {
"Fields.10": "1002",
"Fields.11": "Test2",
"Fields.12": "Fixed2"
}
}
]
}
But i need the data in following format
{
"data": [
{
"TransactionID": "34540d40-7db8-44c1-9a2a-5072c2d01756",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1001"
},
{
"fieldId": "11",
"fieldValue": "Test1"
},
{
"fieldId": "12",
"fieldValue": "Fixed1"
}
]
},
{
"TransactionID": "145800f9-c4a5-4625-84d7-29af5e674a14",
"fieldsList": [
{
"fieldId": "10",
"fieldValue": "1002"
},
{
"fieldId": "11",
"fieldValue": "Test2"
},
{
"fieldId": "12",
"fieldValue": "Fixed2"
}
]
}
]
}
How can i achieve this ? is possible to deserialise using JObject or JArray? Please help.
i have tried to create following model class and tried to deserialise but not getting result as expected.
public class PipeLineResponse
{
public string TransactionID { get; set; }
public List<Dictionary<string, string>> fields { get; set; }
}
public class PipeLineResponseObject
{
public List<PipeLineResponse> data { get; set; }
}
How to create that json in that format any DTO or Automapper will work ? Please help me with samples.
The solution that I am laying down here takes the DTO approach. The response from the service is being deserialized to the DTO, which further is being manually mapped to the final ViewModel that we are sending to the client. By no means, this implementation is production-ready and there is scope for improvement, for which I am adding in comments. But this gives a detailed understanding of how we can handle these kind of scenarios. We are making use of Newtonsoft.Json, which can be pulled into your project via the NuGet package manager.
Structure of the DTO
// RootDTO.cs
// This structure is directly based on the response obtained from remote service.
public class Fields
{
[JsonProperty(PropertyName ="Fields.10")]
public string Fields10 { get; set; }
[JsonProperty(PropertyName = "Fields.11")]
public string Fields11 { get; set; }
[JsonProperty(PropertyName = "Fields.12")]
public string Fields12 { get; set; }
}
public class Datum
{
public string Tranid { get; set; }
public Fields fields { get; set; }
}
public class RootDTO
{
[JsonProperty(PropertyName ="data")]
public List<Datum> data { get; set; }
}
Structure of ViewModel
// PipelineResponse.cs
public class FieldsList
{
public string fieldId { get; set; }
public string fieldValue { get; set; }
}
public class ResponseDatum
{
[JsonProperty(PropertyName = "TransactionID")]
public string TransactionID { get; set; }
public List<FieldsList> fieldsList { get; set; }
}
public class PipelineResponse
{
public List<ResponseDatum> data { get; set; }
}
Deserializing the response to the DTO
// ...other code
var responseString = await httpResponseMessage.Content.ReadAsAsync<Object>();
// This is where the DTO object is created. This should be mapped to view model type.
var responseDTO = JsonConvert.DeserializeObject<RootDTO>(responseString);
Mapping the DTO to ViewModel
The mapping from DTO type to ViewModel type needs to be done before sending the response to the client. It is the view model type that is sent to the client. This logic can be placed within a separate helper (ideally, to separate concerns) or any other location as per the practices you are following.
public PipelineResponse ConvertResponseDTOToResponse(RootDTO responseDTO)
{
// FieldId is being hardcoded here. Instead, you can use Reflection to
// fetch the property name, split on '.' and take the item at index 1.
// Notice that DTO properties have "JsonProperty" attributes for this.
try
{
List<ResponseDatum> responseList = new List<ResponseDatum>();
if (responseDTO != null)
{
// Reflection can be used to avoid hardcoding on 'fieldId'
foreach (var item in responseDTO.data)
{
var responseDataObj = new ResponseDatum
{
TransactionID = item.Tranid,
fieldsList = new List<FieldsList>
{
new FieldsList
{
fieldValue = item.fields.Fields10,
fieldId = "10"
},
new FieldsList
{
fieldValue = item.fields.Fields11,
fieldId = "11"
},
new FieldsList
{
fieldValue = item.fields.Fields12,
fieldId = "12"
}
}
};
responseList.Add(responseDataObj);
}
}
// This object is what you return from your controller endpoint finally.
// The serialized response of this object is of the json structure you need
return new PipelineResponse { data = responseList };
}
catch (Exception ex)
{
throw ex;
}
}

Deserializing the JSON in the C# console application

I want to deserialize the JSON response from the web service call in the C# Console application.JSON looks like
{
"il_response": {
"custom_forms": [
{
"id": 84,
"name": "Request",
"note": "Notes",
"fields": [
{
"label": "Prj",
"value": [
"ABC",
"DEF"
],
"name": "Projects"
},
{
"label": "Submit Date",
"value": "October 16, 2017 ",
"name": "Submit Date"
},
{
"label": "Name",
"value": "Dhana",
"name": "Name"
}
]
}
],
"il_metadata": {}
}
}
I have all the POCO in the seperate class file called iDTO.cs
public class iResponse
{
public iResponse(){ }
public List<iDTO> data { get; set; }
}
public class iDTO
{
public iDTO() { }
}
public class Field
{
public string label { get; set; }
public object value { get; set; }
public string name { get; set; }
}
public class C_Form
{
public int id { get; set; }
public string name { get; set; }
public string note { get; set; }
public List<Field> fields { get; set; }
}
public class IlMetadata
{
}
public class IlResponse
{
public List<C_Form> c_forms { get; set; }
public IlMetadata il_metadata { get; set; }
}
public class RootObject
{
public IlResponse il_response { get; set; }
}
Below is my code where I am calling the service
public class APICall
{
string BaseUR = ConfigurationManager.AppSettings["BaseURL"];
string accessToken = ConfigurationManager.AppSettings["AccessToken"];
public async Task<IHttpActionResult> Get()
{
using (var client = new HttpClient())
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
Uri uri = new Uri(BaseURL);
client.BaseAddress = uri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var response = await client.GetAsync(uri);
var datafile = await response.Content.ReadAsStringAsync();
var returnDataObj = JsonConvert.DeserializeObject<iLabDTO.RootObject>(datafile);
}
}
}
Here I am not sure how to get each name and value property from the field in the JSON. I see that we can use the for each with the fields but not surehow to get both the value and name
This worked using your json, after amending the problem mentioned by Luke. However I'm using iDTO.RootObject whereas your api says iLabDTO.RootObject.
string datafile = File.ReadAllText(#"json.txt");
var returnDataObj = JsonConvert.DeserializeObject<iDTO.RootObject>(datafile);
foreach (var form in returnDataObj.il_response.c_forms)
{
Console.WriteLine(form.id);
Console.WriteLine(form.name);
Console.WriteLine(form.note);
foreach(var field in form.fields)
{
Console.WriteLine(field.name);
Console.WriteLine(field.label);
Console.WriteLine(field.value);
}
}
The c_forms property on your IlResponse object will need to have the same name as the corresponding property on your JSON object:
{
"il_response": {
"custom_forms": [
From the above code snippet, you should rename the c_forms property to custom_forms instead.
That's the only occurrance of that issue that I see, but you will need to make sure that all of your C# property names match up with the JSON object names that are being received. This will then give you the property name, as it is in your C# model object, and the value, which will be held inside of the named property at runtime.

How do I get a property from a list when parsing JSON in C# with JSON.NET?

I'm able to parse simple properties using JSON.NET with this C# code:
Code C#
WebClient c = new WebClient();
var data = c.DownloadString("http://localhost/json1.json");
JObject o = JObject.Parse(data);
listBox1.Items.Add(o["name"]);
listBox1.Items.Add(o["email"][0]);
listBox1.Items.Add(o["email"][1]);
listBox1.Items.Add(o["website"]["blog"]);
json1.json
{
"name": "Fname Lname",
"email": [
"email#gmail.com",
"email#hotmail.com"
],
"website":
{
"blog": "example.com"
}
}
json2.json
{
"name": "Fname Lname",
"email": [
"email#gmail.com",
"email#hotmail.com"
],
"website":
{
"blog": "example.com"
},
"faculty":
{
"department": [
{
"name": "department.name",
"location": "department.location"
}
]
}
}
From the second JSON file, I'm not able to get name and location from the department. How do I do that in C#?
name : department.name
location: department.location
yourjsonobject.faculty.department[0].name;
yourjsonobject.faculty.department[0].location;
Here is some jsfiddle to help you with this:
http://jsfiddle.net/sCCrJ/
var r = JSON.parse('{"name": "Fname Lname","email": [ "email#gmail.com", "email#hotmail.com"],"website":{ "blog": "example.com"},"faculty":{ "department": [ { "name": "department.name", "location": "department.location" } ]}}');
alert(r.faculty.department[0].name);
alert(r.faculty.department[0].location);
for (var i = 0; i < r.faculty.department.length; i++) {
alert(r.faculty.department[i].name);
}
Your problem is that department is an array of objects (though it happens to just contain one item here), but you're not accessing it like it is. You can use o["faculty"]["department"][0]["name"] to get your data.
You might want to use classes (here are ones auto-converted with http://json2csharp.com/) to more easily work with your data.
public class Website
{
public string blog { get; set; }
}
public class Department
{
public string name { get; set; }
public string location { get; set; }
}
public class Faculty
{
public List<Department> department { get; set; }
}
public class RootObject
{
public string name { get; set; }
public List<string> email { get; set; }
public Website website { get; set; }
public Faculty faculty { get; set; }
}
Then you can get all of the data (instead of hoping the fixed indexes are right, and that you didn't make a typo in the property names) with this code:
WebClient c = new WebClient();
var data = c.DownloadString("http://localhost/json1.json");
var o = JsonConvert.DeserializeObject<RootObject>(data);
listBox1.Items.Add(o.name);
foreach (var emailAddr in o.email)
listBox1.Items.Add(emailAddr);
listBox1.Items.Add(o.website.blog);
foreach (var dept in o.faculty.department)
{
listBox1.Items.Add(dept.name);
listBox1.Items.Add(dept.location);
}

Categories