Passing an Array of object results in errors - c#

I have created an API in ASP.NET Core 2.2 framework as per below sample
[HttpPost]
[Authorize]
public IActionResult AddInvoiceRest([FromBody]AddInvoiceRetailRest[] InvoiceDetail)
{
}
here AddInvoiceRetailRest is class object. I want to pass multiple objects as array.
I am doing testing with postman. I have passed this array from raw body as per below sample.
{
"InvoiceDetail": [
{
"InvoiceMst": [
{
"InvoiceNo": 0,
"CustId": 0,
"SubTotal": 93,
"TaxAmount": 13
}
]
}
]
}
problem is here in api i received blank array without adding [Frombody] and when i add [FromBody] , Api doesn't call and shows error like below
{
"InvoiceDetail": [
"The input was not valid."
]
}
definition of class is
public class AddInvoiceRetailRest
{
public AddInvoiceMst[] InvoiceMst { get; set; }
public AddInvoiceItemDetail[] InvoiceItemDetail { get; set; }
public AddInvoicePaymentDetail[] InvoicePaymentDetail { get; set; }
[Optional]
public AddInvoiceItemLogDetail[] InvoiceItemLog { get; set; }
[Optional]
public string BillDetail { get; set; }
[Optional]
public PumpCartObject[] InvoicePumpCart { get; set; }
[Optional]
public InvoiceFeeOrDeposite[] InvoiceFeeOrDeposite { get; set; }
}
Here in the question, I just put a sample of the request, not all keys.
Can someone please let me know what I'm doing wrong?

Your issue is that you are expecting array in your API but you are passing a single object json and not an array.
Try this:
[
{
"InvoiceMst":
[
{
"InvoiceNo": 0,
"CustId": 0,
"SubTotal": 93,
"TaxAmount": 13
}
]
}
]

The posted data does not match the expectation of the action.
One option is to create a model that matches the expected data
public class InvoiceDetailModel {
public AddInvoiceRetailRest[] InvoiceDetail { get; set; }
}
And bind to that in the action
[HttpPost]
[Authorize]
public IActionResult AddInvoiceRest([FromBody]InvoiceDetailModel model) {
if(ModelState.IsValid) {
AddInvoiceRetailRest[] invoiceDetail = model.InvoiceDetail;
//...
}
return BadRequest(ModelState);
}

Related

ASP.NET MVC app - how to send data in body of a POST

I'm trying out my hand at ASP.NET. For now, I'm just trying to prove to myself that I can get a json array.
I have the following code:
[Route("widgets")]
[HttpPost]
[AllowAnonymous]
public string createbulkwidgets([FromBody] string request)
{
return request;
}
I'm using POSTMAN to send the following:
POST to http://localhost:5000/widgets
and I have defined a body - raw - json that includes this:
{
"cars": [
{ "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] },
{ "name":"BMW", "models":[ "320", "X3", "X5" ] },
{ "name":"Fiat", "models":[ "500", "Panda" ] }
]
}
Problem
When I try to run my code, the request string is always NULL.
I'm not sure what I'm doing wrong.
No compile / build errors though.
Try this:
public class CarsItem
{
public string Name { get; set; }
public List<string> Models { get; set; }
}
public class Root
{
public List<CarsItem> Cars { get; set; }
}
[Route("widgets")]
[HttpPost]
[AllowAnonymous]
public Root CreateBulkWidgets([FromBody] Root request)
{
return request;
}
You got null request string because ASP.NET will convert the JSON to a instance according to the JSON format, so you should define a model to receive it
https://learn.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api

Json Value doesn't assign to the List [HttpPost]

Since am new to web api, i am finding some difficulty to post json List to Web API.
Json
[
{
"ItemId":20,
"RegId":"VISIT0001778",
"BLoadDetailId":"8/31/2018 12:28:10 PM",
"OrderReferenceNo":null,
"StartTime":"0001-01-01T00:00:00",
"InvalidItemMsg":"",
"InvalidItemstatus":false,
"BLoadingBay":"Chute 009",
"BLoadingBayCode":null,
"BLoadingBayID":7,
"RFID":7123,
"GangId":2,
"BOrderTransfer":false,
"BLoadedBags":0.0,
"BRemainingBags":0.0,
"BConversionValue":null,
"WHid":2
}
]
class :
public class clsStartTimeUpdate
{
public int ItemId { get; set; }
public string RegId { get; set; }
public string BLoadDetailId { get; set; }
public string OrderReferenceNo{ get; set; }
public DateTime StartTime { get; set; }
public string InvalidItemMsg { get; set; }
public bool InvalidItemstatus { get; set; }
public string BLoadingBay { get; set; }
public string BLoadingBayCode { get; set; }
public int? BLoadingBayID { get; set; }
public long? RFID { get; set; }
public int? GangId { get; set; }
public bool BOrderTransfer { get; set; }
public decimal BLoadedBags { get; set; }
public decimal BRemainingBags { get; set; }
public string BConversionValue { get; set; }
public int? WHid { get; set; }
}
Json request
http://localhost:49290/api/config/Post?StartTimeDetails=[enter image description here][1][{%22ItemId%22:20,%22RegId%22:%22VISIT0001778%22,%22BLoadDetailId%22:%228/31/2018%2012:28:10%20PM%22,%22OrderReferenceNo%22:null,%22StartTime%22:%222001-01-01T00:00:00%22,%22InvalidItemMsg%22:%22%22,%22InvalidItemstatus%22:false,%22BLoadingBay%22:%22Chute%20009%22,%22BLoadingBayCode%22:null,%22BLoadingBayID%22:7,%22RFID%22:7123,%22GangId%22:2,%22BOrderTransfer%22:false,%22BLoadedBags%22:0.0,%22BRemainingBags%22:0.0,%22BConversionValue%22:null,%22WHid%22:2}]
Method WebAPI
[HttpPost]
public HttpResponseMessage Post([FromUri]List<clsStartTimeUpdate> StartTimeDetails)
{
return base.BuildSuccessResult(HttpStatusCode.OK, StartTimeDetails);
}
result:
[{"ItemId":0,"RegId":null,"BLoadDetailId":null,"OrderReferenceNo":null,"StartTime":"0001-01-01T00:00:00","InvalidItemMsg":null,"InvalidItemstatus":false,"BLoadingBay":null,"BLoadingBayCode":null,"BLoadingBayID":null,"RFID":null,"GangId":null,"BOrderTransfer":false,"BLoadedBags":0.0,"BRemainingBags":0.0,"BConversionValue":null,"WHid":null}]
return result doesnot assign the values as in the Json.
May be this is a simple situation , but i really appreciate the help.
It seems that you want to convey your json with HttpGet request instead of HttpPost then you can follow below,
1) Send Json with HttpGet
Method: Get
Url: http://localhost:49290/api/config/MyGet?StartTimeDetails=[{%22ItemId%22:20,%22RegId%22:%22VISIT0001778%22,%22BLoadDetailId%22:%228/31/2018%2012:28:10%20PM%22,%22OrderReferenceNo%22:null,%22StartTime%22:%220001-01-01T00:00:00%22,%22InvalidItemMsg%22:%22%22,%22InvalidItemstatus%22:false,%22BLoadingBay%22:%22Chute%20009%22,%22BLoadingBayCode%22:null,%22BLoadingBayID%22:7,%22RFID%22:7123,%22GangId%22:2,%22BOrderTransfer%22:false,%22BLoadedBags%22:0.0,%22BRemainingBags%22:0.0,%22BConversionValue%22:null,%22WHid%22:2}]
Web Api Method:
[HttpGet]
public HttpResponseMessage MyGet(string StartTimeDetails)
{
List<clsStartTimeUpdate> clsStartTimeUpdates = JsonConvert.DeserializeObject<List<clsStartTimeUpdate>>(StartTimeDetails);
return base.BuildSuccessResult(HttpStatusCode.OK, StartTimeDetails);
}
Note: Its bad practice to send huge json in query string, so for use HttpPost instead
2) Send Json with HttpPost
Method: Post
Url: http://localhost:49290/api/config/MyPost
Data:
[
{
"ItemId":20,
"RegId":"VISIT0001778",
"BLoadDetailId":"8/31/2018 12:28:10 PM",
"OrderReferenceNo":null,
"StartTime":"0001-01-01T00:00:00",
"InvalidItemMsg":"",
"InvalidItemstatus":false,
"BLoadingBay":"Chute 009",
"BLoadingBayCode":null,
"BLoadingBayID":7,
"RFID":7123,
"GangId":2,
"BOrderTransfer":false,
"BLoadedBags":0.0,
"BRemainingBags":0.0,
"BConversionValue":null,
"WHid":2
}
]
Web Api Method:
[HttpPost]
public HttpResponseMessage MyPost([FromBody]List<clsStartTimeUpdate> StartTimeDetails)
{
return base.BuildSuccessResult(HttpStatusCode.OK, StartTimeDetails);
}
For complex types Always use [FromBody] in the argument.
[HttpPost]
public HttpResponseMessage Post([FromBody]List<clsStartTimeUpdate> StartTimeDetails)
{
return base.BuildSuccessResult(HttpStatusCode.OK, StartTimeDetails);
}
And then specify your query object in Body.
Note: To specify the value in the body, You will need an API client like Postman or Swagger.
https://www.getpostman.com/
In Postman,
Select Post method and specify the URL,
Then go to "Body" tab and select raw.
Specify JSON as type.
In the body, paste your data.
{ [
{
"ItemId":20,
..........
}
]}
The Other answer by #ershoaib is the real fix for the problem that OP is facing. However, I am leaving this answer as it is the standard which should be followed.
Since you are using post you should expect the data in the controller method to come from body. See related issue here

C# - Deserialize Json Object with value thas has variable content

when do a POST request to a web API the response could be returned in two ways:
{
"Response": {
"StatusCode": 200,
"StatusMessage": "OK",
"Content": {
"auth_hash": "606ca0e7802a070531b4b2fd8ee5fc17b4649a19"
}
}
}
or
{
"Response": {
"StatusCode": 200,
"StatusMessage": "OK",
"Content": {
"document": {
"loja": 5,
"numero": 85099,
"doc": "FS",
"data": "2017-12-13",
"cliente": 0,
"nome": "CONSUMIDOR FINAL",
"liquido": 1.1504,
"total": 1.3,
"anulado": 0,
"emp": 5,
"pago": 1,
"datapag": "2017-12-13",
"tipo": 0,
"pagamento": 1,
"datahora": "2017-12-13 12:51:51",
"deve": 0,
"idcx": 240403,
"mesa": 1001,
"mesaidx": 0,
"lugar": 0
}
}
}
}
How can I deserialize the value "Content" into a C# class object being this values variable?
Best Regards
I assume you know which call can return which response. Then a solution could be to create a generic container, and provide the expected type as generic argument. So the container looks like this:
public class ResponseContainer<TContent>
{
public Response<TContent> Response { get; set; }
}
public class Response<TContent>
{
public int StatusCode { get; set; }
public string StatusMessage { get; set; }
public TContent Content { get; set; }
}
Then you create (or rather, generate) a class per response type:
public class DocumentContent
{
public Document document { get; set; }
}
public class Document
{
public int loja { get; set; }
// ...
public int lugar { get; set; }
}
Then you can deserialize into the type you want, by varying the TContent argument, in this case DocumentContent:
string json = PerformDocumentCall();
var deserialized = JsonConvert.DeserializeObject<ResponseContainer<DocumentContent>>(json);
And for the auth response you pass AuthContent:
public class AuthContent
{
public string auth_hash { get; set; }
}
string json = PerformAuthCall();
var deserialized = JsonConvert.DeserializeObject<ResponseContainer<AuthContent>>(json);
Apart from reading and parsing the raw string and looking for clues, a very easy way is to simply deserialize into one POCO first (using Json.NET or similar). If all values are empty, you try the next type. The order in which you deserialize could be decided out from what's most common or expected in the specific use case.
Or, if you feel slightly more adventurous you could deserialize it into a dynamic, and simply check if response.Content.document exists. Very little code, but not as "strict" as above.

How to return complex Json object in asp.net mvc

I am using entity framework to get data from database and serialize it to JSON. And I want my JSON response looks like the one below.
Shoud I add items property to my model and make JSON I want? Thanks.
Desired Json
{
"items" : [
{
"Id": 1,
"AdContent":"Content1"
},
{
"Id": 2,
"AdContent":"Content2"
},
{
"Id": 3,
"AdContent":"Content3"
}
]
}
Current JSON I receive
[
{
"Id":1,
"AdContent":"Content1"
},
{
"Id":2,
"AdContent":"Content2"
},
{
"Id":3,
"AdContent":"Content3"
}
]
{
Controller
public JsonResult GetJson()
{
using (var db = new DoskaUsContext())
{
List<AdViewModel> list = db.Ads.Select(x => new AdViewModel
{
Id = x.AdId,
AdContent = x.AdContent
}).ToList();
return Json(list, JsonRequestBehavior.AllowGet);
}
}
Model
public class AdViewModel
{
public int Id { get; set; }
public string AdContent { get; set; }
}
Anonymous object is one solution Json(new {items=list},...).
General approach to solve that problem - generate strongly typed classes with http://json2csharp.com/ and populate result via generated classes or at least see what is missing from your code.
In this particular case generated code:
public class Item
{
public int Id { get; set; }
public string AdContent { get; set; }
}
public class RootObject
{
public List<Item> items { get; set; }
}
Which shows missing piece of the puzzle - RootObject with list property items.
Create another model which hold collection of AdViewModel as items
public class AdViewModel
{
public int Id { get; set; }
public string AdContent { get; set; }
}
public class NewModel
{
public AdViewModel items { get; set; }
}

Deserialize JSON with a list of two objects, one being a list of that object

I am trying to de-serialize a weird complex json string but having issues. I am getting an exception:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Response' because the type requires a JSON object (e.g. {"name":"value"})
The Json looks like this
{
"success":true,
"error":null,
"response":{
"responses":[
{
"success":true,
"error":null,
"response":{
"ob":{
"icon":"sunny.png",
"weatherShort":"Sunny"
}
},
"request":"requeststring"
},
{
"success":true,
"error":null,
"response":[
{
"indice":{
"current":{
"dateTimeISO":"2016-08-09T10:00:00-05:00",
"indexENG":"dry"
}
}
}
],
"request":"requeststring"
}
]
}
}
The problem when trying to create a C# class is that inside the responses list there is a Response object and a Response list.
Here is my class structure:
public class Responses
{
public bool success { get; set; }
public object error { get; set; }
public Response response { get; set; }
public List<Response> responses { get; set; }
public string request { get; set; }
}
public class Indice
{
public Current current { get; set; }
}
public class Current
{
public string indexENG { get; set; }
public string dateTimeISO { get; set; }
}
public class Ob
{
public string icon { get; set; }
public string weatherShort { get; set; }
}
public class Response
{
public List<Responses> responses { get; set; }
public Indice indice { get; set; }
public Ob ob { get; set; }
}
public class RootJsonObject
{
public bool success { get; set; }
public object error { get; set; }
public Response response { get; set; }
}
Am I doing something completely wrong here to handle the Responses list with a Response object and a Response list?
In case anyone wants to know, here is how I deserialize it:
RootJsonObject obj = JsonConvert.DeserializeObject<RootJsonObject>(response);
response being the string from a web request.
I am just trying to figure out how to map this strange JSON to a C# class. I've tried quite a few different class structures but seem to get the same exception regardless. I've also tried c# class generators but they don't give a decent output for this particular JSON. Appreciate any input! Thanks!
There is an error in your JSON. Second element in array has square brackets wrapping classic curly brackets, as if response was a collection but it's not. It's expected to be of type Response:
{
"success": true,
"error": null,
"response": [ <<<HERE {
"indice": {
"current": {
"dateTimeISO": "2016-08-09T10:00:00-05:00",
"indexENG": "dry"
}
}
}] <<<HERE,
"request": "requeststring"
}
Final, proper JSON that you should have received would look like this:
{
'success': true,
'error': null,
'response': {
'responses': [{
'success': true,
'error': null,
'response': {
'ob': {
'icon': 'sunny.png',
'weatherShort': 'Sunny'
}
},
'request': 'requeststring'
}, {
'success': true,
'error': null,
'response': {
'indice': {
'current': {
'dateTimeISO': '2016-08-09T10:00:00-05:00',
'indexENG': 'dry'
}
}
},
'request': 'requeststring'
}]
}
}

Categories

Resources