MVC controller : get JSON object from HTTP body?
Asked Answered
M

6

85

We have an MVC (MVC4) application which at times might get a JSON events POSTed from a 3rd party to our specific URL ("http://server.com/events/"). The JSON event is in the body of the HTTP POST and the body is strictly JSON (Content-Type: application/json - not a form-post with JSON in some string field).

How can I receive the JSON body inside the controller's body? I tried the following but didn't get anything

[Edit]: When I say didn't get anything I meant that jsonBody is always null regardless of whether I define it as Object or string.

[HttpPost]
// this maps to http://server.com/events/
// why is jsonBody always null ?!
public ActionResult Index(int? id, string jsonBody)
{
    // Do stuff here
}

Note that I know if I give declare the method with a strongly typed input parameter, MVC does the whole parsing and filtering i.e.

// this tested to work, jsonBody has valid json data 
// that I can deserialize using JSON.net
public ActionResult Index(int? id, ClassType847 jsonBody) { ... }

However, the JSON we get is very varied, so we don't want to define (and maintain) hundreds of different classes for each JSON variant.

I'm testing this by the following curl command (with one variant of the JSON here)

curl -i -H "Host: localhost" -H "Content-Type: application/json" -X POST http://localhost/events/ -d '{ "created": 1326853478, "data": { "object": { "num_of_errors": 123, "fail_count": 3 }}}
Monastery answered 24/10, 2012 at 1:37 Comment(2)
so how will you parse hundreds of different variants of JSON then, using if/else?Chuipek
@TheVillageIdiot: they are dumped to logs as a one JSON object each. So that's why I only care about them as a JSON object or a string - don't care what's inside them.Monastery
M
170

It seems that if

  • Content-Type: application/json and
  • if POST body isn't tightly bound to controller's input object class

Then MVC doesn't really bind the POST body to any particular class. Nor can you just fetch the POST body as a param of the ActionResult (suggested in another answer). Fair enough. You need to fetch it from the request stream yourself and process it.

[HttpPost]
public ActionResult Index(int? id)
{
    Stream req = Request.InputStream;
    req.Seek(0, System.IO.SeekOrigin.Begin);
    string json = new StreamReader(req).ReadToEnd();

    InputClass input = null;
    try
    {
        // assuming JSON.net/Newtonsoft library from http://json.codeplex.com/
        input = JsonConvert.DeserializeObject<InputClass>(json)
    }

    catch (Exception ex)
    {
        // Try and handle malformed POST body
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

    //do stuff

}

Update:

for Asp.Net Core, you have to add [FromBody] attrib beside your param name in your controller action for complex JSON data types:

[HttpPost]
public ActionResult JsonAction([FromBody]Customer c)

Also, if you want to access the request body as string to parse it yourself, you shall use Request.Body instead of Request.InputStream:

Stream req = Request.Body;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
Monastery answered 29/10, 2012 at 6:26 Comment(7)
Note, if you close StreamReader, it closes the stream by default, so if you have anything else reading the stream, make sure you use the overload with leaveOpen: false (I forget if the stream is read-once in MVC or not, I know it is in WebAPI)Wiltshire
It's better to use Model parameters rather than manually reading and deserializing.Titmouse
Yes, but that wasn't possible since it was a 3rd party API.Earleanearleen
@Titmouse how? can you provide an example. This is because DeepSpace101's answer is working but looks to be too much effort. I thought ASP.NET MVC has some easier way to getting this value from ajax call. Thanks in advance.Ld
@PawanPillai you simply use InputClass as the parameter for the Index action method. ASP.NET MVC will automatically bind the incoming JSON to the model obect. Reading the input stream is only useful when the structure of the JSON sent to a single endpoint can change.Viva
Thank you , you saved my timeChinkapin
Thanks! I have been searching for a solution for hours and this worked!Kaitlynkaitlynn
E
6

use Request.Form to get the Data

Controller:

    [HttpPost]
    public ActionResult Index(int? id)
    {
        string jsonData= Request.Form[0]; // The data from the POST
    }

I write this to try

View:

<input type="button" value="post" id="btnPost" />

<script type="text/javascript">
    $(function () {
        var test = {
            number: 456,
            name: "Ryu"
        }
        $("#btnPost").click(function () {
            $.post('@Url.Action("Index", "Home")', JSON.stringify(test));
        });
    });
</script>

and write Request.Form[0] or Request.Params[0] in controller can get the data.

I don't write <form> tag in view.

Equilateral answered 24/10, 2012 at 5:17 Comment(5)
There is no form in the HTML POST body - the body of the HTML POST is pure json. So Request.Form[0] = null (it's count is 0).Monastery
Not having a <form> tag doesn't matter - the HTTP header from your code is Content-Type: application/x-www-form-urlencoded; charset=UTF-8. Check the output in fiddler. That's what makes it looks like a FORM submission.Monastery
jQuery uses form encoded data by default when posting AJAX content, that's why the backend gets Form populatedSlay
where does it say jquery is posting data?Earleanearleen
As long as Content-Type: application/x-www-form-urlencoded; was set, Request.Form[0] works greatRhebarhee
R
3

I've been trying to get my ASP.NET MVC controller to parse some model that i submitted to it using Postman.

I needed the following to get it to work:

  • controller action

    [HttpPost]
    [PermitAllUsers]
    [Route("Models")]
    public JsonResult InsertOrUpdateModels(Model entities)
    {
        // ...
        return Json(response, JsonRequestBehavior.AllowGet);
    }
    
  • a Models class

    public class Model
    {
        public string Test { get; set; }
        // ...
    }
    
  • headers for Postman's request, specifically, Content-Type

    postman headers

  • json in the request body

    enter image description here

Reforest answered 17/7, 2019 at 17:57 Comment(0)
R
2

If you are sending raw data from postman body with Content-Type: application/json then it's consider as Stream data. please find the following way to get that.

[HttpPost]
public async Task<IActionResult> Post()
{
            
    string Header_Value = string.Empty;
    if (Request.Headers.TryGetValue("Sequeritykey", out var headerValues))
    {
       Header_Value = headerValues;
    }
           
    StreamReader requestReader = new StreamReader(Request.Body);
    JObject request = JObject.Parse(await requestReader.ReadToEndAsync());
    return Ok();
}
Rascality answered 11/2, 2023 at 14:57 Comment(0)
S
1

Once you define a class (MyDTOClass) indicating what you expect to receive it should be as simple as...

public ActionResult Post([FromBody]MyDTOClass inputData){
 ... do something with input data ...
}

Thx to Julias:

Parsing Json .Net Web Api

Make sure your request is sent with the http header:

Content-Type: application/json

Slenderize answered 13/7, 2017 at 14:43 Comment(3)
That would work in WebAPI, the question refers to MVC.Adapter
It actually doesn't matter whether you're using WebAPI or MVC. As long as client sends a JSON payload that complies with yout DTO, this will work.Messenger
@Messenger If you're using Core, but MVC 5 for example, this will not work.Bibbs
R
0

you can get the json string as a param of your ActionResult and afterwards serialize it using JSON.Net

HERE an example is being shown


in order to receive it in the serialized form as a param of the controller action you must either write a custom model binder or a Action filter (OnActionExecuting) so that the json string is serialized into the model of your liking and is available inside the controller body for use.


HERE is an implementation using the dynamic object

Rist answered 24/10, 2012 at 5:26 Comment(1)
you can get the json string as a param of your ActionResult - how? That's the original question as I'm unable to get jsonBody with data. jsonBody == null even if I define jsonBody as string or Object !Monastery

© 2022 - 2024 — McMap. All rights reserved.