How to Handle a Request with application/json Content in ASP.NET Core
By FoxLearn 3/1/2025 3:15:36 AM 145
However, if the request uses an unsupported content type, such as application/json
, the framework might not be able to handle the deserialization automatically, and it will respond with a 415 – Unsupported Media Type
error.
In this article, I’ll guide you through creating a custom InputFormatter for application/json
requests, and I’ll show you how to configure the action method to correctly handle this content type.
Note: While another approach could involve manually reading the Request.Body
with a StreamReader
in the action method, using an InputFormatter is a cleaner and more efficient solution.
Create Your Own InputFormatter for application/json
For example, how to implement a custom InputFormatter that can process application/json
requests.
using Microsoft.AspNetCore.Mvc.Formatters; public class JsonSingleValueFormatter : InputFormatter { private const string ApplicationJson = "application/json"; public JsonSingleValueFormatter() { SupportedMediaTypes.Add(ApplicationJson); } public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context) { try { using (var reader = new StreamReader(context.HttpContext.Request.Body)) { string jsonContent = await reader.ReadToEndAsync(); // Convert the JSON string to the target model type (parameter type in the action method) var model = JsonSerializer.Deserialize(jsonContent, context.ModelType); return InputFormatterResult.Success(model); } } catch (Exception ex) { context.ModelState.TryAddModelError("BodyJsonValue", $"{ex.Message} ModelType={context.ModelType}"); return InputFormatterResult.Failure(); } } protected override bool CanReadType(Type type) { // Define which types this formatter can handle return type == typeof(string) || type == typeof(int) || type == typeof(DateTime); } public override bool CanRead(InputFormatterContext context) { return context.HttpContext.Request.ContentType == ApplicationJson; } }
This custom formatter reads the request body as a string, deserializes it into the specified model type, and handles any errors by updating the ModelState
. If there’s a deserialization error, the framework will respond with the standard "problem details" error format.
Register the InputFormatter
Once you’ve created your custom InputFormatter, you need to register it in the InputFormatters
collection.
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(mvcOptions => { mvcOptions.InputFormatters.Add(new JsonSingleValueFormatter()); }); // Continue with other initialization code
Use [FromBody] to Bind the Parameter
Next, to receive the deserialized value in your action method, use the [FromBody]
attribute on the parameter:
[HttpPost()] [Consumes("application/json")] public IActionResult Post([FromBody] string name) { return Ok($"Posted value={name}"); }
This ensures that your action method is expecting application/json
data in the body and deserializes it appropriately.
Now that the custom InputFormatter is registered and the action method is set up to handle JSON input, let’s test this functionality with examples.
Post a String
Send a POST request with a string in the body and set the Content-Type
to application/json
:
POST /Example Content-Type: application/json "Bob"
This will return a 200 OK
response with:
Posted value Bob
Post an Integer
The custom InputFormatter looks at the parameter type and tries to convert the request body to that type. Here's an example of receiving an integer in a JSON request:
[HttpPost()] [Consumes("application/json")] public IActionResult Post([FromBody] int age) { return Ok($"Posted age={age}"); }
Send the following request:
POST /Example Content-Type: application/json 1
This returns a 200 OK
response with:
Posted age=1
Error Response
If the body contains invalid data (e.g., a string when an integer is expected), the custom InputFormatter will populate the ModelState
with the error details.
Here’s an example where we send invalid data for an integer:
POST /Example Content-Type: application/json "not an int"
This triggers a 400 Bad Request
response with a standard problem details error:
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "00-7d905c800640e2870c0dfacf28d89586-6ef5d985832817f4-00", "errors": { "BodyJsonValue": [ "Input string was not in a correct format. ModelType=System.Int32" ] } }
By creating a custom InputFormatter, you can handle requests with unsupported content types like application/json
in a cleaner, more maintainable way.
- How to securely reverse-proxy ASP.NET Core
- How to Retrieve Client IP in ASP.NET Core Behind a Reverse Proxy
- Only one parameter per action may be bound from body in ASP.NET Core
- The request matched multiple endpoints in ASP.NET Core
- How to Create a custom model validation attribute in ASP.NET Core
- How to disable ModelStateInvalidFilter in ASP.NET Core
- How to fix LoginPath not working in ASP.NET Core
- Synchronous operations are disallowed