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.
CodePudding user response:
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>());
CodePudding user response:
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