Cannot deserialize the current JSON object .Net Core 5 - json

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; }
}
}

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.

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;

How to fix, MVC model null issue if int is pass as null from json

I am using formio to produce forms from json in my asp.net core mvc web application. My model definition is given below.
public class MyRootModel
{
public Data data { get; set; }
public class Data
{
public Client client { get; set; }
public Contact contact { get; set; }
}
}
public class Client
{
public string Forename { get; set; }
public string Surname { get; set; }
public int? Gender { get; set; }
public DateTime DateofBirth { get; set; }
}
public class Contact
{
public string City { get; set; }
public string Street { get; set; }
public string Street2 { get; set; }
}
The post method on my controller is given below.
[HttpPost]
public MyResponse Next([FromBody] MyRootModel formCollection)
{
MyResponse myResponse = new MyResponse ();
myResponse.ReturnType = "Success";
myResponse.ReturnMessage = "Well done";
return myResponse ;
}
The Gender on the form is a html5 select type. When the form is submitted, formCollection object on my controller is initialised automatically as json is passed from the client side. However, if user does not select any value in the Gender drop down, then the formCollection is appearing as null. I have looked at the json being passed and noticed that "gender": "null" is passed and this is the reason formCollection is appearing null. Even though I have defined Gender as int? in my client model.
I am displaying json submitted from the form below for both scenarios. The first scenario works fine when user selects Gender.
formCollection is initialised properly
{
"data": {
"client": {
"forename": "abc",
"surname": "def",
"gender": 2
},
"contact": {
"city": "ghi",
"street": "jkl"
},
"submit": true
},
"metadata": {}
}
formColletion is becoming null when following json is passed
{
"data": {
"client": {
"forename": "dsfaasdf",
"surname": "asdf",
"gender": "null"
},
"contact": {
"city": "asdf",
"street": ""
},
"submit": true
},
"metadata": {}
}
I thought that int? allows null so I changed the Gender type from int to int? but still not working.
{
"data": {
"client": {
"forename": "dsfaasdf",
"surname": "asdf",
"gender": null
},
"contact": {
"city": "asdf",
"street": ""
},
"submit": true
},
"metadata": {}
}
Try passing the gender as null instead of "null".This is beacause the gender propert in the model class Client in your code ,is in int but you are trying to pass a string.

Not able to conver json to dataset, datatable

I am writing a small tool to convert json to csv. First I try to convert json to Dataset or Datatable but failing.
The Json string is:
{
"id1": {
"id": "id11",
"cards": {
"1": {
"id": "test11",
"fingerprint": "test11",
"last4": "test11",
"exp_month": 7,
"exp_year": 2019,
"brand": "test11"
},
"0": {
"id": "test12",
"fingerprint": "test12",
"last4": "test12",
"exp_month": 7,
"exp_year": 2020,
"brand": "Visa"
},
"2": {
"id": "test13",
"fingerprint": "test13",
"last4": "test13",
"exp_month": 8,
"exp_year": 2020,
"brand": "Visa"
}
}
},
"id2": {
"id": "id21",
"cards": {
"1": {
"id": "test21",
"fingerprint": "test21",
"last4": "test21",
"exp_month": 7,
"exp_year": 2019,
"brand": "MC"
},
"0": {
"id": "test22",
"fingerprint": "test22",
"last4": "test5",
"exp_month": 2,
"exp_year": 2020,
"brand": "Visa"
}
}
}
}
I tried
DataSet ds = JObject.Parse(jsonContent)["root"].ToObject<DataSet>();
DataTable dt = JsonConvert.DeserializeObject<DataTable>(jsonContent);
But it does not work. Gives this error with first one:
An unhandled exception of type 'System.NullReferenceException' occurred in JsonToCsv.exe
Additional information: Object reference not set to an instance of an object.
This error with second one:
An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
Additional information: Unexpected JSON token when reading DataTable. Expected StartArray, got StartObject. Path '', line 1, position 1.
Any suggestion would be appreciated
I managed to parse json into a list and then converted list to csv. the code to parse json to list is as follows:
public class Card
{
public string ActId { get; set; }
public string CustId { get; set; }
public string Id { get; set; }
public string Fingerprint { get; set; }
public string Last4 { get; set; }
public int Exp_month { get; set; }
public int Exp_year { get; set; }
public string Brand { get; set; }
}
public static List<Card> JsonToCSV(string JsonContent)
{
var ds = JObject.Parse(JsonContent);
var cards = new List<Card>();
foreach (var item in ds)
{
var crds= JObject.Parse(JsonConvert.DeserializeObject(item.Value["cards"].ToString()).ToString());
foreach (var crd in crds)
{
var card =JsonConvert.DeserializeObject<Card>(crd.Value.ToString());
card.ActId= item.Key;
card.CustId= item.Value["id"].ToString();
cards.Add(card);
}
}
return cards;
}

Deserialize complex object with 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; }
}