Jeremy Morren
Jeremy Morren

Reputation: 764

ASP.NET Core - bind multiple controller parameters to body

Good Day All

I am using ASP.NET Core 3.1. I need to bind controller parameters to body (they are too large to fit in the URL). I do not wish to create a DTO just for a single method (I also have multiple endpoints, which will end up requiring a lot of throwaway DTOs). This isn't possible out of the box, and all current online help seems to be focused to the old .NET Framework Web Api.

In simple terms, given the following controller:

public class GreetController : ControllerBase
{
    public string Index(string firstname, string lastname) 
        => $"Hello {firstname} {lastname}";
}

The following curl command:

curl -X GET --header "Content-Type: application/json" --data \
    "{\"firstname\":\"John\",\"lastname\":\"Doe\"}" https://[Url]/Greet/

should return Hello John Doe, but instead the parameters are null. Adding [FromBody] also does not work. I need this to work for Json and Xml request bodies. I am aware that this can be done with URI parameters. However, I have some parameters which are too large for a URI therefore they must be in the request body.

NB 2: Please do not include a long-winded explanation about why this doesn't comply with REST.

Upvotes: 2

Views: 3444

Answers (3)

alphons
alphons

Reputation: 143

Use nuget package Mvc.ModelBinding.MultiParameter

You can skip all the attributes when having unique names.

Upvotes: 0

Rena
Rena

Reputation: 36645

Here are two things you need to know:

1.FromBody could not work with Get request.

2.Don't apply [FromBody] to more than one parameter per action method. Once the request stream is read by an input formatter, it's no longer available to be read again for binding other [FromBody] parameters.

For you do not want to pass the data by query and do not want to create dtos,I suggest that you could using Newtonsoft.Json.Linq.JObject:

public class GreetController : ControllerBase
{
    [HttpPost]
    public string Index([FromBody]JObject model)
    { 
        var firstname = model["firstname"].ToString();
        var lastname = model["lastname"].ToString();
        return $"Hello {firstname} {lastname}"; 
    }
}

Startup.cs:

services.AddControllers()
    .AddNewtonsoftJson();

For how to use Newtonsoft.Json in an ASP.NET Core 3.1 project:

https://learn.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&tabs=visual-studio#use-newtonsoftjson-in-an-aspnet-core-30-mvc-project

Result: enter image description here

Another way is to custom model binder,you could follow the answer below:

https://stackoverflow.com/a/60611928/11398810

Upvotes: 5

Rod Ramírez
Rod Ramírez

Reputation: 1368

That scenario seems ideal for a QueryString request. Example:

GET: [Url]/Greet/?firstName=Rod&lastName=Ramirez

where:

public class GreetController : ControllerBase
{
    public string Index([FromQuery] string firstname, string lastname) 
        => $"Hello {firstname} {lastname}";
}

Not tested, but this should work 😁

Upvotes: -1

Related Questions