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
Related
var stringResult = await HttpHelper.PostAsync(batchUrl, content);
I am getting following result as an API response in C# in above stringResult variable after calling above line. I want to convert below "Items" value to C# list. In every result, first GUID is different. How to convert the below result in C# List. I want only Items.
{
"0934009e-6518-4440-91e3-c252d2e2cc4f": {
"Status": 200,
"Headers": {
"Content-Type": "application/json; charset=utf-8"
},
"Content": {
"Items": [{
"Timestamp": "2021-10-18T14:00:00Z",
"Value": 20.7,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-10-25T14:00:00Z",
"Value": 15.9,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-01T14:00:00Z",
"Value": 14.8,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-08T15:00:00Z",
"Value": 20.1,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-15T15:00:00Z",
"Value": 19.5,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-22T15:00:00Z",
"Value": 19.7,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-29T15:00:00Z",
"Value": 20.4,
"UnitsAbbreviation": "ppm"
}
]
}
}
}
When some part of the json structure is unknown, you need to explore it manually. There are several ways to do it, but I'm used to passing JObject :
var root = JObject.Parse(text);
// Unknown name property, then iterate
// When the object has one property, First is a good fit
var response = root.First as JProperty;
var guid = response.Name;
var itemsJson = response.Value["Content"]["Items"];
var items = itemsJson.ToObject<List<Item>>();
you can try this code
List<Item> items = JObject.Parse(stringResult).Properties()
.First().Value["Content"]["Items"].ToObject<List<Item>>();
public class Item
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public string UnitsAbbreviation { get; set; }
}
go to https://json2csharp.com/
convert your json to C# class.
since your root node is dynamic guid, you cannot directly use class structure deserialization but you can use a inner nodes
Pseudo Program
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient w = new WebClient();
string json = w.DownloadString(new Uri("https://jsonkeeper.com/b/GETO"));
var firstObject = JObject.Parse(json);
var guid = firstObject.Properties().Select(p => p.Name).FirstOrDefault();
//Console.Write(guid);
Root output = firstObject[guid].ToObject<Root>();
Console.Write(output.Content.Items.Count());
The DTO structure
public class Root
{
public int Status { get; set; }
public Headers Headers { get; set; }
public Content Content { get; set; }
}
public class Content
{
public List<Item> Items { get; set; }
}
public class Headers
{
[JsonProperty("Content-Type")]
public string ContentType { get; set; }
}
public class Item
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public string UnitsAbbreviation { get; set; }
}
here's fiddle: https://dotnetfiddle.net/w5fO0w
I have used below code to get items -
var resultObjects = AllChildren(JObject.Parse(json))
.First(c => c.Type == JTokenType.Array )
.Children<JObject>();
foreach (JObject result in resultObjects)
{
foreach (JProperty property in result.Properties())
{
}
}
And method is -
private static IEnumerable<JToken> AllChildren(JToken json)
{
foreach (var c in json.Children())
{
yield return c;
foreach (var cc in AllChildren(c))
{
yield return cc;
}
}
}
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; }
}
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;
}
}
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
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.