trying to receive JSON as a JObject - c#

I am trying to bring in JSON data into my method. I am using Postman to send my data.
An example of my JSON is...
{"FieldData" : {"name": "david"}, "Project" : 20, "Version" : 1}
My model is
public class IncomingFormData
{
public JObject FieldData { get; set; }
public int Project { get; set; }
public int Version { get; set; }
}
My method is
[HttpPost]
public void SaveFormData(IncomingFormData FieldData)
{
string myField = FieldData.FieldData.ToString();
}
I am getting null in FieldData.FieldData and the Project and Version are showing 0.
In my earlier version that worked, I had...
An example of my JSON is...
{FieldData : '{"name": "david"}', "Project" : 20, "Version" : 1}
[HttpPost]
public void SaveFormData(string FieldData, int Project, int Version)
{
string myField = FieldData;
}
Unfortunately for me, in this version, if the value of one of the FieldData objects has an apostrophe in it, it fails. (This is correct according to the RFC).
So, I had to rewrite it.
Now, I can't get anything coming in from Postman. The method is called but nothing coming in.
Postman has Accept application/json and content-type application/json set.
Thank you.

This is not really the way I wanted to do this, but hey, it works.
My original method was in a regular MVC controller. When I tried to send the JSON, I was getting the error Cannot create abstract class
However, creating an api controller instead, with pretty much the same signature JObject FieldData and from there, passing into my regular controller, it just works.
The code below is in the api controller.
public JsonResult Post([FromBody]JObject FieldData)
{
//string myData = FieldData.ToString();
FormsController form = new FormsController();
return form.SaveFormData(FieldData);
}

Try pass this: {"IncomingFormData":{"FieldData" : {"name": "david"}, "Project" : 20, "Version" : 1}}

Related

C# Receiving empty object in controller

I'm trying to get some data from the request body in a POST Controller, but the console shows empty props:
The Post Controller:
[HttpPost("{id}/features")]
public ActionResult<bool> AddFeatureAsync(Guid Id, [FromBody] AddRoleFeatureRequest request)
{
Console.WriteLine(request.Name);
Console.WriteLine(request.Description);
Console.WriteLine(request.Id);
return true;
}
The AddRoleFeatureRequest class:
public class AddRoleFeatureRequest
{
public Guid Id;
public string? Name;
public string? Description;
}
The JSON data from Postman (Using body raw as Json):
{
"name": "Feature ABC",
"description": "description",
"id": "7e12b0ad-2c82-46f0-a69e-8538efb0aa60"
}
What am I doing wrong?
I'm trying to get some data from the request body in a POST
Controller, but the console shows empty props:
Your reason for getting null data on your console or in controller is pretty obvious because you have defined your AddRoleFeatureRequest class field only which doesn't allow to set any value on it. For instance, public string? Name; is a field not property. To set value, you must implement valid setter. Thus, it can be treated as valid property and able to assign value into it.
Solution:
public class AddRoleFeatureRequest
{
public Guid Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
}
Note: Property without getter and setter will always consider as field, it will not allow you to assign value from outside.
Output:
Note: Modifying your class defination would completely resolve your issue. No other changes required.
Your "AddRoleFeatureRequest" class has capitals and your json data does not. This could be the source of your problems.
the attribute names might be the reasons because they ar different then the json keys, retry it while considering letters cases,

ASP.NET Core 3.1 Binding to List<int> (generic lists) property not working

I am trying to implement a controller method inside of NopCommerce under ASP.NET Core 3.1 that looks like this:
[HttpPost]
[Route("CustomerSchool/Update")]
public IActionResult Update(CustomerSchoolMappingModel model)
{
}
my model looks like this:
public class CustomerSchoolMappingModel : BaseNopModel
{
public int CustomerId { get; set; }
public List<int> SchoolIds { get; set; } = new List<int>();
}
When I submit a http POST with the following form data:
CustomerId: 1
SchoolIds[0]: 2
SchoolIds[1]: 3
My properties are successfully binding but not the SchoolIds property collection which is always returning empty.
I suspect that NopCommerce has replaced the default modelbinders (which I believe support this functionality by default in ASP.NET) but I am not 100% sure how to correctly replace/implement this functionality.
I believe using a custom IModelBinderProvider to fix this issue could work but I am wondering what is the correct/best way to fix this problem and ensure I can correctly bind generic lists using the name[x] form schema in my ASP.NET Core application?
I think you are missing [FromForm] attribute on method argument in the controller and the argument name in your request. I've never used NopCommerce. Here are correct collection formats when sending form data: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-3.1#collections. This request's body should work:
model.CustomerId=1&model.SchoolIds[]=12&model.SchoolIds[]=321
This code works fine for me without any custom model binders:
public class FormDto
{
public int Id { get; set; }
public List<int> ListOfIds { get; set; }
}
[Route("api/[controller]")]
[ApiController]
public class FormController : ControllerBase
{
[HttpPost]
[Route("post")]
public ActionResult Post([FromForm] FormDto dto)
{
Console.WriteLine(JsonConvert.SerializeObject(dto, Formatting.Indented));
return Ok();
}
}
I tested it with Invoke-WebRequest in Powershell:
iwr -uri http://localhost:5000/api/form/post -Method Post -Body 'dto.Id=13&dto.ListOfIds[]=1&dto.ListOfIds[]=2&dto.ListOfIds[]=34' -ContentType 'application/x-www-form-urlencoded'
Output in console:
{
"Id": 13,
"ListOfIds": [
1,
2,
34
]
}
So for anyone interested it seems to boil down to Nop not liking using Generic lists.
I reviewed the default binders used by Nop from here and
I was able to successfully resolve my problem by changing my model to this:
public class CustomerSchoolMappingModel : BaseNopModel
{
public int CustomerId { get; set; }
public ICollection<int> SchoolIds { get; set; } = new List<int>();
}

OWIN ApiController access to the request body/stringified JSON

This is in OWIN & .Net 4.5.2
Using debug I'm proving this controller's method is being called by the web request.
My thing is the request body contains a JSON stringified object:
"{ 'id':'12', 'text1':'hello', 'test2':'world' }"
Which is applicably encoded as it is transferred on the line.
I've tried so many things I'm so confused now.
How do I get the decoded string so I can JSON.Parse() that or better yet get .Net to just given me an object?
In one version (long ago now) I had a defined type for this object. If I need that great, not a high challenge. But if I only have the JSON object from the string that's fine too.
public class cController : ApiController {
[HttpPut]
public string put(string id) {
var bdy = this.Request.Content;
//Console.WriteLine("PUT containers {0}", body);
return string.Empty;
}
}
In case it helps, the bdy.ContentReadStream is null. I don't know if this is good, bad, or important. Maybe Request.Content isn't the way to go but seems to me like if I'm going to read the body as a stream then it shouldn't be null.
I also tried working through System.Web.HttpContext. If that is somehow the answer I have no problem going back to that. But I couldn't find the secret sauce.
Pass the desired model as a parameter to the action and the frame work should be able to parse it provided it is valid JSON
public class cController : ApiController {
[HttpPut]
public IHttpActionResult Put(string id,[FromBody] Model body) {
if(ModelState.IsValue) {
return Ok(body.text1);
}
return BadRequest();
}
}
Where Model is defined as
public class Model {
public string id { get; set; }
public string text1 { get; set; }
public string test2 { get; set; }
}

send neatly formatted json data to asp.net web api instead of default [FromBody] behavior

I am trying to figure out a way to send a Json formatted data to a web api controller in a neat(more natural) way.
let me explain. Suppose I have this controller:
[HttpPost]
public class StudentController : ApiController
{
public void PostSomething([FromBody] string name, [FromBody] Student s)
{
//do something
}
}
The json data that I WANT to post is something like this (as it is correctly formatted):
{
"name" : "John",
"student" : {
"id" : "1",
"age" : "22"
}
}
But what I SHOULD send for the web api to parameter bind the objects should be like this:
{
"John",
{
"id" : "1",
"age" : "22"
}
}
The problem is that if I use my desired json format, both name and student objects will be null in the PostSomething method of the controller.
How can I send a json request with a format similar to the first example to my web api controller?
In order to consume the desired JSON structure you can change the method signature of the PostSomething and introduce a class that represents the sent data. E.g.
public class StudentTransferObject {
public string Name {get; set;}
public Student Student {get; set;}
}
With the Controller:
[HttpPost]
public class StudentController : ApiController
{
public void PostSomething([FromBody] StudentTransferObject studentInformation)
{
//do something
}
}
Read text from response body and parse the objects yourself:
[HttpPost]
public async Task<string> PostSomething()
{
string result = await Request.Content.ReadAsStringAsync();
//parse here how you want
return result;
}
Dynamic serialization with custom binding or JToken.

Parsing json in ASP.NET MVC4 controller

json is passed from browser using POST method to ASP.NET MVC4 application controller in server.
It contains properites from which 3 are arrays of 0.. 20 elements (in code below all of them
have only 1 element).
How to parse this json in C# ?
I tried controller with signature
public JsonResult RegisterSales(Sale mysale)
but mysale properties are not assigned.
passed json:
{ "id":"sale1",
"sale_date":"2013-11-10 19:20:44"
"taxes":[{"id":"km20pr","name":"20%","rate":0.2}],
"products":[{"id":"prod1",
"sale_id":"sale1",
"register_id":"register1",
"quantity":"1.00000"}],
"payments":[{"id":"payment1",
"sale_id":"sale1",
"register_id":"register1",
"amount": 0
}]
}
It should parsed to C# structure something like
public class Sale
{
public string id;
public DateTime sale_date;
public Tax[] taxes;
public Product[] products;
public Payment[] payments;
}
public class Tax
{
public string id, name;
public decimal rate;
}
public class Product
{
public string id, sale_id, register_id;
public decimal quantity;
}
public class Payment
{
public string id, sale_id, register_id;
public decimal amount;
}
Use NewtonSoft JSON Deserialize, like so:
class School
{
public string student;
public object[] data;
}
School datum = JsonConvert.Deserialize<School>(jsonStr);
//Do stuff with datum...
Enjoy.
You need to post data with correct content type. In this case it's application/json. MVC chooses correct binding mode based on the content type used to send data to a server.
The best thing to do is to have the same name for the json as for your accepting variable "mysale".
Example:
"mysale": { "id":"sale1",
"sale_date":"2013-11-10 19:20:44"
"taxes":[{"id":"km20pr","name":"20%","rate":0.2}],
"products":[{"id":"prod1",
"sale_id":"sale1",
"register_id":"register1",
"quantity":"1.00000"}],
"payments":[{"id":"payment1",
"sale_id":"sale1",
"register_id":"register1",
"amount": 0
}]
}
You can do this by adding the name in the AJAX call by so:
$.ajax({
...,
...,
data: JSON.stringify({mysale:data}),
...,
...
});
Now it will accept your JSON.
The reason for this is that the JSON posted will be viewed as a post value, and just like with a normal form you can catch this value by its name.
So to answer your question: adding {get;set;} is not the best way to go.

Categories

Resources