Post generic class in .net core web API - c#

I'm using .net core Web API. I'm posting generic QueryFilter class from angular. But, generic part of class return null. When, i change to parameter like this, it is working perfectly :
public async Task<ServiceResult> GetStudentsForGrid([FromQuery]QueryFilter queryFilter,[FromQuery]StudentFilter studentFilter)
{ } //This working perfectly
QueryFilter.cs
public class QueryFilter<T> where T : class
{
public string SortBy { get; set; }
public bool IsSortAscending { get; set; }
public int PageFirstIndex { get; set; }
public byte PageSize { get; set; }
public T CustomFilter { get; set; }
}
StudentFilter.cs
public class StudentFilter
{
public string Name { get; set; }
public string Surname { get; set; }
}
Controller.cs (not working)
[HttpGet("GetStudentsForGrid")]
public async Task<ServiceResult> GetStudentsForGrid([FromQuery]QueryFilter<StudentFilter> queryFilter)
{ } //This not working
I don't want to send every time two parameter. So, I want to use generic way. How can i fix this null exception?

If you want to use a "generic" way , let's say your controller action is :
public IActionResult GetStudentsForGrid([FromQuery]QueryFilter<StudentFilter> queryFilter)
{
var x= queryFilter;
return new JsonResult(x);
}
you have to sent the request with a well formatted querystring :
GET https://localhost:5001/api/students?sortBy=Hello&pageSize=10&customFilter.Name=1&customFilter.SurName=2 HTTP/1.1
Note the way we pass the parameters of customFilter.Name and customFilter.SurName.
The response will be :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{
"sortBy": "Hello",
"isSortAscending": false,
"pageFirstIndex": 0,
"pageSize": 10,
"customFilter": {
"name": "1",
"surname": "2"
}
}

Related

.NET Core API REST C# List into List is null

I'm developing an api in net core.
I've done a post function in which I send an object containing multiple parameters and a list within another list.
When I'm debugging the code the function is called correctly but I find that the second list always arrives null.
The rest of the data arrives at you correctly. I have done different tests with other objects and everything works correctly.
It is this case in which the list within another the second one arrives null.
My code:
example request input
{
"Name": "TestName",
"Related1":
[{
"id1": "TestNameRelated1",
"Related2":
[{
"id2": "TestNameRelated2"
}]
}]
}
[HttpPost]
public resultExample Test([FromBody]TestClass test)
{
//do something
}
[DataContract]
public class TestClass
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<TestClassArray> Related1 { get; set; }
}
[DataContract]
public class TestClassArray
{
[DataMember]
public string id1 { get; set; }
[DataMember]
public List<TestClassArray2> Related2 { get; set; }
}
[DataContract]
public class TestClassArray2
{
[DataMember]
public string id2 { get; set; }
}
This api was previously made in .NET framework 4.8 and this case worked correctly.
Now I'm passing the api to .Net5.
Could it be that in .Net5 it is not allowed to pass lists within other lists?
Do you have to enable some kind of configuration to be able to do this now?
You need use class/DTO with constructor like shown below and you should be good to go. I have uploaded this sample API app's code working with .net5.0 on my GitHub here.
public class TestClass
{
public TestClass()
{
Related1 = new List<TestClassArray>();
}
public string Name { get; set; }
public List<TestClassArray> Related1 { get; set; }
}
public class TestClassArray
{
public TestClassArray()
{
Related2 = new List<TestClassArray2>();
}
public string id1 { get; set; }
public List<TestClassArray2> Related2 { get; set; }
}
public class TestClassArray2
{
public string id2 { get; set; }
}
public class ResultExample
{
public string StatusCode { get; set; }
public string Message { get; set; }
}
Controller Post Method
[HttpPost]
[ProducesResponseType(typeof(ResultExample), 200)]
public ResultExample Post([FromBody] TestClass test)
{
ResultExample testResult = new ResultExample();
TestClass test2 = new TestClass();
TestClassArray testClassArray = new TestClassArray();
TestClassArray2 testClassArray2 = new TestClassArray2();
test2.Name = test.Name;
foreach (var item in test.Related1)
{
foreach (var item2 in item.Related2)
{
testClassArray2.id2 = item2.id2;
}
testClassArray.Related2.Add(testClassArray2);
}
test2.Related1.Add(testClassArray);
Console.WriteLine(test2);
testResult.Message = "New Result added successfullly....";
testResult.StatusCode = "201";
return testResult;
}
Swagger Input Sample Payload
Post Controller Result
Response of Sample input payload,(You can change it to default 201 response code as well)
I had a similar issue.
API method shows List was null
In my case a date field was not well formatted
So I use SimpleDateFormat on Android Studio with a correct datetime format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",Locale.US);
item.setDate(dateFormat.format(calendar.getTime()));
and works fine

Combine URL data with HTTP POST request body in ServiceStack

I'd like to be able to POST data like this to a REST API:
POST /foo/b HTTP/1.1
Accept: application/json
Content-Type: application/json
{ "Qux": 42, "Corge": "c" }
The URL segment after foo (i.e. b) also contains data that I need to capture in a server-side variable. I've tried to implement this feature in ServiceStack (see code below), but the response body is null.
Here's first the request type:
[Route("/foo/{Bar}", "POST")]
public class PostFooRequest : IReturn<PostFooResponse>
{
public string Bar { get; set; }
[ApiMember(ParameterType = "body")]
public Foo Body { get; set; }
}
As you can see, Bar is a URL variable. The Foo class is defined like this:
public class Foo
{
public int Qux { get; set; }
public string Corge { get; set; }
}
Furthermore, the response looks like this:
public class PostFooResponse
{
public string Bar { get; set; }
public Foo Foo { get; set; }
}
Finally, the service itself is defined like this:
public class ReproService : Service
{
public object Post(PostFooRequest request)
{
return new PostFooResponse { Bar = request.Bar, Foo = request.Body };
}
}
Notice that this method simply echoes the values of the request in the response.
When I execute the above request, I only get the Bar value back:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"bar":"b"}
Setting a breakpoint in the Post method reveals that request.Body is null.
How do I write the code so that the API has the desired contract?
FWIW, I'm aware of this question, but the answer only explains what the problem is; not how to solve it.
If you would translate your current request to the following DTO the serializer should be able to fill the properties:
[Route("/foo/{Bar}", "POST")]
public class PostFooRequest : IReturn<PostFooResponse>
{
public string Bar { get; set; }
public int Qux { get; set; }
public string Corge { get; set; }
}
The serializer has no way to know how to deserialize the object you're sending.
Looking at your DTO and the request I would expect a different request.
POST /foo/b HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"Foo": { "Qux": 42, "Corge": "c" }
}
Other way of retrieving the FormData would be using the following property in your Servicestack service
Request.FormData. Make sure you're not calling the DTO but capital Request.

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

asp.net core web api Post form data with brackets

I'm running server build with asp.net core (v2.1) web api and have this REST HTTP call:
POST http://website.com/callback
with the headers:
...
Content-Type: application/x-www-form-urlencoded
and the body:
response%5Bkey%5D=123&response%5Bname%5D=hi
I want to receive this message at this point:
[HttpPost]
[Route("callbacks")]
public ActionResult Hook([FromForm]Model model)
{
// <---- Model has instance but empty fields
return Ok();
}
My Model is:
public class Model
{
public string key { get; set; }
public string name { get; set; }
}
Somehow the brackets ("[key]" and "[name]") are not being parsed into my model instance. They are null both, although I provide them in body.
How to solve it?
You should set name in form for your properties:
public class Model
{
[FromForm(Name = "response[key]")]
public string key { get; set; }
[FromForm(Name = "response[name]")]
public string name { get; set; }
}

JSON passed to ApiController doesn't deserialize string values

I'm trying to pass a JSON array to an ApiController but the string values aren't deserializing (they are set to null values). The strange thing is that I still get the correct number of elements.
A have an ApiController:
[RoutePrefix("api/language")]
public class LanguagePairApiController : ApiController
With a post method:
// POST: api/language/create
[HttpPost]
[Route("create")]
public string Create([FromBody]LanguagePair[] languagePairs)
I'm sending JSON to it:
[
{"Key":"Test","Value":"Test","Version":"1.0"},
{"Key":"Areyousure","Value":"Are you sure?","Version":"1.0"},
{"Key":"File","Value":"File","Version":"1.0"}
]
And this is the class I'm trying to map it to:
public class LanguagePair
{
public string Key { get; set; }
public string Value { get; set; }
public string Version { get; set; }
}
But the string values are coming through as null:
What am I missing?
EDIT: I've figured out one answer to this and posted it below. But I'm still looking for a better answer...
I figured it out. I needed to decorate the class with DataContract and DataMember attributes:
{
[DataContract]
public class LanguagePair
{
[DataMember]
public string Key { get; set; }
[DataMember]
public string Value { get; set; }
[DataMember]
public string Version { get; set; }
}
}
Read Parameter Binding in ASP.NET Web API
You need to remove [FromBody] attribute from your action...
// POST: api/language/create
[HttpPost]
[Route("create")]
public string Create(LanguagePair[] languagePairs) { ... }
and you can keep your class lean as you originally had it:
public class LanguagePair
{
public string Key { get; set; }
public string Value { get; set; }
public string Version { get; set; }
}
Using [FromBody]
To force Web API to read a simple type from the request body, add the
[FromBody] attribute to the parameter:
public HttpResponseMessage Post([FromBody] string name) { ... }
In this example, Web API will use a media-type formatter to read the
value of name from the request body. Here is an example client
request.
POST http://localhost:5076/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:5076
Content-Type: application/json
Content-Length: 7
"Alice"
When a parameter has [FromBody], Web API uses the Content-Type
header to select a formatter. In this example, the content type is
"application/json" and the request body is a raw JSON string (not a
JSON object).

Categories

Resources