Pawel
Pawel

Reputation: 1297

ASP.NET core - how to pass optional [FromBody] parameter?

How do I pass optional (nullable) [FromBody] parameter in ASP.NET Core (5.0)? If I don't send body in my request I get 415 Unsupported Media Type error. Can this be configured and if so, how to do it on a controller or action, rather than an app level? I presume it has to do something with model validation, but not sure. Thanks.

[HttpGet("[action]")]
public async Task<IActionResult> GetElementsAsync([FromBody] IEnumerable<int> elements = default)
{
  var result = await dataService.GetData(elements);
  return Ok(result);
}

EDIT: To clarify:

This is typical scenario and it works normally: This is typical scenario and it works normally

But passing empty body is returning 415 right away without even reaching action: Passing empty body is returning 415 right away without reaching action

Upvotes: 18

Views: 26589

Answers (6)

ashkufaraz
ashkufaraz

Reputation: 5297

add this line to configuration

services.AddControllers().ConfigureApiBehaviorOptions(options => { options.SuppressModelStateInvalidFilter = true; });

automatic-http-400-responses

Upvotes: 0

Jeka Developer
Jeka Developer

Reputation: 151

As per filters execution flow diagram https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1 ResourceFilters are executed before model binding so you can make a hack and set content-type in order model binder to not crash so you can accept request with no body and content-type header passed from client

public class MediaTypeResourceFilterAttribute : Attribute, IResourceFilter
{
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
           context.HttpContext.Request.ContentType ??= "application/json";
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
}

Upvotes: 0

Tomasz Juszczak
Tomasz Juszczak

Reputation: 2340

I will address some points that were not mentioned here.

  1. To get rid of 415 without sending Content-Type you need to create your custom consumer of the Content-Type

https://stackoverflow.com/a/65813534/2531209

But I would say this is an overkill

  1. If you pass Content-Type: application/json in your request header you will get "Body cannot be empty" (Tested on .NET 6) and only then @Nicola answer comes in handy.

From my tests it looks like modifications to the controller are not needed and only FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow) is enough with nullable type as parameter.

  1. Or you can change nothing in your current code and send a header Content-Type: application/json with a body of {}. This will bypasses all of those errors, but this is not the most optimal solutions for public API's

Upvotes: 2

Anjum
Anjum

Reputation: 183

With ASP.NET Core 3.1, I could allow nullable optional parameters by implementing Nicola's suggestion:

services.AddControllers(options =>{options.AllowEmptyInputInBodyModelBinding = true;})

Upvotes: 2

Tiny Wang
Tiny Wang

Reputation: 15971

Just add content-type in your request header. Without the content-type:application/json will appear 415 when body is empty.

No changes to your controller. Test in my side is ok.

enter image description here

I created a new asp.net core 5 api project and this is my controller:

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace WebApi_net5.Controllers
{
    public class HomeController : ControllerBase
    {
        [HttpGet("[action]")]
        public string GetElementsAsync([FromBody] IEnumerable<int> elements = default)
        {
            return "value";
        }
    }
}

Upvotes: 11

Nicola Biada
Nicola Biada

Reputation: 2800

You can find a solution here:
https://github.com/pranavkm/OptionalBodyBinding

From this issue on github:
https://github.com/dotnet/aspnetcore/issues/6878

And from .net Core 5 you can use this one:

public async Task<IActionResult> GetElementsAsync([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] IEnumerable<int> elements = default)
...

Also needed (from Pawel experience):

services.AddControllers(options =>{options.AllowEmptyInputInBodyModelBinding = true;})

Upvotes: 14

Related Questions