ASP.NET Core MVC:How to Get Raw JSON Bound to a String Without a Type

ASP.NET Core MVC : How to get raw JSON bound to a string without a type?

The following works in .net core 1.x, but not in .net core 2.x.

As I commented, the solution is to use [FromBody]dynamic data as my parameter list, using dynamic instead of string, and I will receive a JObject.

Caution: If your architecture calls for a single WebApi server to be equally fluent in producing XML and JSON, depending on content-type header entries, this kind of direct-JSON-consumption strategy can backfire on you. (Supporting both XML and JSON on the same service is possible with sufficient work, but then you're taking stuff that was further UP the MVC asset pipeline and moving it down into your controller methods, which turns out to be against the spirit of MVC, where models come to you as POCOs already parsed.)

Once you convert to a string inside the method, converting the incoming JObject (Newtonsoft.JSON in memory data type for JSON) to a string.

Found at other answer here.

Sample code, thanks to Jeson Martajaya:

With dynamic:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]dynamic value)
{
//...
}

Sample code with JObject:

[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]Newtonsoft.Json.Linq.JObject value)
{
//...
}

ASP.NET Core 3.0 [FromBody] string content returns The JSON value could not be converted to System.String.

Not sure this help but I think they made some change in .net core 3.0 Newtonsoft.JSON package so you can try this

Install Microsoft.AspNetCore.Mvc.NewtonsoftJson package.

In your startup.cs add

services.AddControllers().AddNewtonsoftJson();

Recieving uknown JSON to my API and parsing it

System.Text.Json has an class called JsonElement which can be used to bind any JSON to it.

[HttpPost]
public IActionResult Create([FromBody] JsonElement jsonElement)
{
// Get a property
var aJsonProperty = jsonElement.GetProperty("aJsonPropertyName").GetString();

// Deserialize it to a specific type
var specificType = jsonElement.Deserialize<SpecificType>();

return NoContent();
}

MVC controller : get JSON object from HTTP body?

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();

Read raw Request.Body in Asp.Net Core MVC Action with Route Parameters

As I suspected the root cause was MVC inspecting the request body in order to try to bind route parameters. This is how model binding works by default for any routes that are not parameter-less, as per documentation.

The framework however does this only when the request content type is not specified, or when it is form data (multipart or url-encoded I assume).

Changing my request content-type to any thing other than form data (e.g. application/json) I can get the framework to ignore the body unless specifically required (e.g. with a [FromBody] route parameter). This is an acceptable solution for my case since I am only interested accepting JSON payloads with content-type application/json.

Implementation of DisableFormValueModelBindingAttribute in Uploading large files with streaming pointed out by @Tseng seems to be a better approach however, so I will look into using that instead, for complete

Why does this return an escaped string of JSON?

That's a valid string representation of your object. If you do JSON.parse() on that string it works just fine. If you dont want it serialized, then just return the actual object:

[HttpPost]
public IHttpActionResult Post(FormDataCollection formData)
{
return this.Ok(formData);
}


Related Topics



Leave a reply



Submit