Deserialize complex object with Json - json

How would I deserialize this with JSON.NET. I keep getting a "cannot perform binding on a null reference" exception. Here is the code, and the JSON output below:
var json = client.DownloadString("https://myapp.tpondemand.com/api/v1/UserStories?take=999&include=[Tasks[Id,Name,TimeSpent]]&format=json");
dynamic output = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
string nemo = output.items[1].Id[0];
Console.ReadLine();
{
"Items": [
{
"Id": 395,
"Tasks": {
"Items": []
}
},
{
"Id": 394,
"Tasks": {
"Items": []
}
},
{
"Id": 393,
"Tasks": {
"Items": []
}
},
{
"Id": 336,
"Tasks": {
"Items": []
}
},
}
]

If you know Json format just create datacontracts and deserialize them.
For example
[DataContract]
public class ItemJson
{
[DataMember]
public string Id { get; set; }
[DataMember]
public List<TaskJson> Tasks { get; set; }
}
[DataContract]
public class TaskJson
{
[DataMember]
public List<ItemJson> Items{ get; set; }
}

Related

stream writer is not writing to JSON file in webapi

Im trying to write data in a JSON file using webapi but stream writer is not writing data to the file.
JSON File :
{
"Students": [
{
"id": 1,
"name": "Ravi",
"department": "IT"
},
{
"id": 2,
"name": "Raj",
"department": "hr"
},
{
"id": 3,
"name": "avi",
"department": "it"
},
{
"id": 4,
"name": "rome",
"department": "HR"
},
{
"id":5,
"name": "virat",
"department": "HR"
},
{
"id":6 ,
"name": "Tushar",
"department": "RM"
}
]
}
Class
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Department { get; set; }
}
public class Students
{
public List<Student> students { get; set; }
}
Api controller: [HttpPost] method for writing data to the json file.
[Route("api/[controller]")]
[ApiController]
public class StudentsController : ControllerBase
{
[HttpPost]
public IActionResult Add(Students _Student)
{
using (var fs = new FileStream("C:/Users/tanmay_pawar/source/repos/CRUDAPI/CRUDAPI/people.json", FileMode.Append))
using (var sw = new StreamWriter(fs))
{
sw.WriteLine(_Student);
}
}
The data recieved in by _Student is not getting added to the json file.
try this
public IActionResult Add(Students _Student)
{
if(_Student==null || _Student.students==null) return null;
var filePath = #"C:\Users\....\..json";
var json = File.ReadAllText(filePath);
Students students = JsonConvert.DeserializeObject<Students>(json);
students.students.AddRange(_Student.students);
json=JsonConvert.SerializeObject(students);
File.WriteAllText(filePath, json);
}
Try the code like below:
[HttpPost]
public IActionResult Add(Students _Student)
{
string jsonresult = JsonConvert.SerializeObject(_Student);
string path = #"C:\c\people.json";
using(var tw=new StreamWriter(path,true))
{
tw.WriteLine(jsonresult.ToString());
tw.Close();
}
return Ok();
}
result:
Update more picture, add data inside the existing JSON file.

Cannot deserialize the current JSON object .Net Core 5

I have a .Net Core 5 solution that is largely he same as another previous, working solution. In both the controllers are .Net Core 5. In the previous, working one, the services, models and view models are in a 4.7 project. Most of the new solution is working, except for one controller that takes a nested (master/detail) JSON sent in the body of the request. The service is set up to deserialize the JSON into a dataset. The JSON shows as valid in the jsonlint.com validator.
However, I keep getting this error in Postman:
"Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IList`1[Sage100_API.ViewModels.APInvoiceReq]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'APInvoiceRequest', line 2, position 21."
[JsonObjectAttribute] is already in place in the viewmodels involved.
The error occurs when stepping off the final curly bracket in this code in the controller:
public APInvoiceResponseController(IAPInvoiceService apInvoiceService, IOptions<AppSettingsModel> app)
{
APInvoiceService = apInvoiceService;
AppSettings = app;
}
What is different between core 5 and 4.7 in deserializing in NewtonSoft JSON?
edit: adding JSON and code
JSON:
{
"APInvoices": {
"APInvoice": [
{
"APDivisionNo": "00",
"APVendorNo": "0000006",
"PayeeTermsCd": "00",
"HoldPayment": "N",
"SeparateCheck": "N",
"InvoiceNo": "12345",
"InvoiceDate": "2022-04-06",
"BatchNmbr": "490",
"TotalAmount": 150,
"APInvoiceDetails": {
"APInvoiceDetail": [
{
"InvoiceNo": "12345",
"Line": "1",
"Amount": "25.7500",
"GLAcctID": "5000-00-10",
"Comment": "line 1 comment",
"BatchNmbr": "490"
},
{
"InvoiceNo": "12345",
"Line": "2",
"Amount": "75.2500",
"GLAcctID": "5000-00-10",
"Comment": "line 2 comment",
"BatchNmbr": "490"
},
{
"InvoiceNo": "12345",
"Line": "3",
"Amount": "49.00",
"GLAcctID": "5000-00-10",
"Comment": "line 3 comment",
"BatchNmbr": "490"
}
]
},
{
"APDivisionNo": "00",
"APVendorNo": "0000006",
"PayeeTermsCd": "00",
"HoldPayment": "N",
"SeparateCheck": "N",
"InvoiceNo": "12346",
"InvoiceDate": "2022-04-06",
"BatchNmbr": "490",
"TotalAmount": 150,
"APInvoiceDetails": {
"APInvoiceDetail": [
{
"InvoiceNo": "12345",
"Line": "1",
"Amount": "25.7500",
"GLAcctID": "5000-00-10",
"Comment": "line 1 comment",
"BatchNmbr": "490"
},
{
"InvoiceNo": "12345",
"Line": "2",
"Amount": "75.2500",
"GLAcctID": "5000-00-10",
"Comment": "line 2 comment",
"BatchNmbr": "490"
},
{
"InvoiceNo": "12345",
"Line": "3",
"Amount": "49.00",
"GLAcctID": "5000-00-10",
"Comment": "line 3 comment",
"BatchNmbr": "490"
}
]
}
}
]
}
}
Controller:
{
[ApiController]
public class APInvoiceResponseController : ControllerBase
{
//private readonly S100Entities Context;
private readonly IAPInvoiceService APInvoiceService;
private readonly IOptions<AppSettingsModel> AppSettings;
public APInvoiceResponseController(IAPInvoiceService apInvoiceService, IOptions<AppSettingsModel> app)
{
APInvoiceService = apInvoiceService;
AppSettings = app;
}
[HttpPost]
[Route("apinvoice")]
public async Task<IActionResult> Basic([FromBody] IList<APInvoiceReq> apInvoice)
{
try
{
var APInvoices = await APInvoiceService.PostAPInvoices(apInvoice);
try
{
if (apInvoice == null)
{
return BadRequest("Missing transaction data.");
}
if (APInvoices == null)
{
return NotFound();
}
return Ok(APInvoices);
}
catch (System.Exception e)
{
Serilog.Log.Error("Error in APInvoices", e);
APInvoices.SuccessErrorWarningResult.AddError(666, e.ToString());
return Ok(APInvoices);
}
}
catch (System.Exception e)
{
Serilog.Log.Error("Error in APInvoices", e);
return BadRequest();
}
}
}
}
APInvoiceReq class:
{
[JsonObjectAttribute]
[JsonArray]
[Serializable]
public class APInvoiceReq : S100Object<APInvoiceReq>
{
public string APDivisionNo { get; set; }
public string APVendorNo { get; set; }
public string PayeeTermsCd { get; set; }
public string HoldPayment { get; set; }
public string SeparateCheck { get; set; }
public string InvoiceNo { get; set; }
public DateTime InvoiceDate { get; set; }
public string InvoiceComment { get; set; }
public int BatchNmbr { get; set; } //UDF_BATCH_NO
public decimal TotalAmount { get; set; }
public IEnumerable<APInvoiceDetail> APInvoiceDetails { get; set; }
}
}

How to extract only part of the JSON and de-serialize it in .netcore

I have .net core application , where an API is called through HTTPClient.
The response for that API in JSON format is as follows:
{
"ID": 25,
"Customer": "CustomerName",
"total": 100,
"details": [
{
"ItemId": "Item1",
"ItemName": "Name1",
"Price": "10"
},
{
"ItemId": "Item2",
"ItemName": "Name2",
"Price": "50"
},
{
"ItemId": "Item3",
"ItemName": "Name3",
"Price": "40"
}
]
}
I get this response from -- > var response = client.GetAsync(ApiPath).Result;
Now from the response variable I need details only for details like :
{
{
"ItemId": "Item1",
"Price": "10"
},
{
"ItemId": "Item2",
"Price": "50"
},
{
"ItemId": "Item3",
"Price": "40"
}
}
I have a DTO class like this :
public class ItemDetails
{
public string ItemId { get; set; }
public string Price { get; set; }
}
Can anyone help in extracting the details according to the DTO class from the main variable "response".
Many thanks!
Try this if you are using newtonsoft
var token = JObject.Parse(response);//load
var detailsToken = token.SelectToken("details");//select
var itemDetails = detailsToken.ToObject<ItemDetails[]>(); //cast to array
Only the properties that exist on ItemDetails will be mapped
You can deserialize the response into an object and take whatever you like from it.
Use the built-in JSON library in .net-core as following
using System.Text.Json;
using System.Text.Json.Serialization;
then make a Response classes to contain the Response values
public class ResponseObject
{
public int ID { get; set; }
public string Customer { get; set; }
[JsonPropertyName("total")]
public int Total { get; set; }
[JsonPropertyName("details")]
public ItemDetails[] Details { get; set; }
}
public class ItemDetails
{
public string ItemId { get; set; }
public string ItemName { get; set; }
public string Price { get; set; }
}
finally, deserialize and extract whatever you like as following
var o = JsonSerializer.Deserialize<ResponseObject>(response);
ItemDetails[] itemDetails= o.Details;

Deserializing json with dynamic property name

Similar question was asked here Serialize/Deserialize dynamic property name using JSON.NET. I am not able to make it work in my situation as below:
I have the following JSON
{
"notes": {
"data": [{
"book": {
"items": [{
"page": "page 1",
"comment": "Some notes"
},
{
"page": "page 1",
"comment": "Some notes"
}
]
}
},
{
"journal": {
"items": [{
"page": "page 1",
"comment": "Some notes"
},
{
"page": "page 1",
"comment": "Some notes"
}
]
}
},
{
"magazine": {
"items": [{
"page": "page 1",
"comment": "Some notes"
},
{
"page": "page 1",
"comment": "Some notes"
}
]
}
}
]
}
}
Created the following classes for JSON serialization:
public class TestParse
{
public Note Notes { get; set; }
}
public class Note
{
public IList<Data> Data { get; set; }
}
public class Data
{
public Source Source { get; set; }
}
[JsonConverter(typeof(MyConverter))]
public class Source
{
public IList<Items> Items { get; set; }
}
public class Items
{
public string Page { get; set; }
public string Comment { get; set; }
}
public class MyConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Source);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var jo = JObject.Load(reader);
var req = new Data
{
Source = jo.ToObject<Source>()
};
return req;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var req = (Source)value;
var jo = new JObject(
new JObject(req.Items));
jo.WriteTo(writer);
}
}
}
I am still not able to deserialize "Source." Any pointer is appreciated.
In the other question you referenced, the dynamic key was determined by the value of another property in the same object. Hence, a converter was needed.
In your situation, you have dynamic keys, but they are not dependent on anything.
You don't really need a converter here; you can just use a Dictionary to handle the dynamic keys.
Change this line in your Note class:
public IList<Data> Data { get; set; }
to this:
public IList<IDictionary<string, Source>> Data { get; set; }
and remove the [JsonConverter] attribute from your Source class. Then it should work.
(You can also delete the Data class as it is not needed.)
Fiddle: https://dotnetfiddle.net/80lIRI

asp.net core 2.1 json serialization null array is not ignored

I have the following classes:
FormGroupModel has a list of FormFieldModel which has a list of FieldOptionModel.
public class FormGroupModel
{
public string GroupLabel { get; set; }
public IEnumerable<FormFieldModel> Fields { get; set; }
}
public class FormFieldModel
{
public string Name { get; set; }
public string Label { get; set; }
public string ControlType { get; set; }
public IEnumerable<FieldOptionModel> Options { get; set; }
}
public class FieldOptionModel
{
public string Value { get; set; }
public string Label { get; set; }
}
I configured Json serializationsettings in Startup.cs to NullValueHandling.Ignore. Null values for my other API return values are all ignored as expected. This object serialization still does not get rid of the Options array when it's empty. I also tried DefaultValueHandling.Ignore but does not work either. How can I get the Options list to be ignored when empty?
[
{
"groupLabel": "Basic Information",
"fields": [
{
"name": "ProjectDescription",
"label": "Project Description",
"controlType": "multiline",
"options": []
},
{
"name": "ProjectId",
"label": "Project Id",
"controlType": "textfield",
"options": []
},
{
"name": "ProjectName",
"label": "Project Name",
"controlType": "textfield",
"options": []
},
{
"name": "ProjectScope",
"label": "Project Scope",
"controlType": "multiline",
"options": []
}