Similar to this old question about prior ASP.NET versions, I want to get the request body of an HTTP POST to be bound to a string. It seems that the method binds, but that value
is null, when ASP.NET invokes my controller method:
namespace Demo.Controllers
{
[Route("[controller]")]
public class WebApiDemoController : Controller
{
...
// POST api/values
[HttpPost]
public System.Net.Http.HttpResponseMessage Post([FromBody]string value)
{
// expected: value = json string, actual: json = null.
}
Do I still have to go grab the body from a stream? Or should this just work? When testing the above method, I used the following http headers:
Accept: Application/json
Content-Type: Application/json;charset=UTF-8
I'm passing in the following in the body: { "a": 1 }
I do NOT want to bind to a string variable named a. I want to bind any JSON I get, and then I want to use the JSON content, any arbitrary content at all, from within my method.
If I understood the documentation, the [FromBody]
attribute should have done what I wanted, but I'm guessing that the ASP.NET core MVC binding mechanism won't bind a json to a "string value", but perhaps I could do something else that gets me an equivalent level of flexibility.
A similar question here gives me the idea maybe I should have written [FromBody] dynamic data
instead of using [FromBody] string value
.
Update: This kind of trick should be thought about before doing it, because if you wanted to have the .net core framework handle JSON and XML encoding for you, you just killed that capability. Certain types of REST servers can and often do have requirements to support both XML and JSON content-types, at least ones I have encountered which have standards documents.
The cleanest option I've found is adding your own simple InputFormatter:
public class RawJsonBodyInputFormatter : InputFormatter
{
public RawJsonBodyInputFormatter()
{
this.SupportedMediaTypes.Add("application/json");
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
using (var reader = new StreamReader(request.Body))
{
var content = await reader.ReadToEndAsync();
return await InputFormatterResult.SuccessAsync(content);
}
}
protected override bool CanReadType(Type type)
{
return type == typeof(string);
}
}
And in your Startup.cs inside ConfigureServices:
services
.AddMvc(options =>
{
options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
});
That will let you get at the raw JSON payload in your controllers:
[HttpPost]
public IActionResult Post([FromBody]string value)
{
// value will be the request json payload
}