简体   繁体   中英

Error: Action has more than one parameter bound from request body

I wrote a new method into my Controller of my ASP.Net MVC project and getting error below. I think InvalidOperationException coming from with Swagger. I marked it as "ignored Api" hoping it will skip the method but error still there:

[ApiExplorerSettings(IgnoreApi = true)]
public decimal CalculatePriceWithCampaign(
       BeverageCapacityCampaign campaign, 
       BeverageCapacity capacity,
       int count = 1)
{
    switch (campaign.DiscountType)
    {
        case DiscountType.Fixed:
            return (capacity.CapacityPrice - campaign.DiscountValue) * count;
        case DiscountType.Percentage:
            return (capacity.CapacityPrice * count) * campaign.DiscountValue;
        default:
            return capacity.CapacityPrice;
    }
}

But when running I am getting this error:

An unhandled exception occurred while processing the request.

InvalidOperationException: Action 'Gorilla.WebApi.Source.Controller.Campaigns.BeverageCapacityCampaignController.CalculatePriceWithCampaign (Gorilla.WebApi)' has more than one parameter that was specified or inferred as bound from request body. Only one parameter per action may be bound from body. Inspect the following parameters, and use 'FromQueryAttribute' to specify bound from query, 'FromRouteAttribute' to specify bound from route, and 'FromBodyAttribute' for parameters to be bound from body:
BeverageCapacityCampaign campaign
BeverageCapacity capacity

Information I could find suggested to check nugets, but all my Nugets are up-to-date.

The error is coming from model binding and is not related to Swagger (the presence of ApiExplorerSettings attribute has no impact on error).

You have two complex parameters. ie of Complex types

BeverageCapacityCampaign 
BeverageCapacity 

The default for Model Binding is to bind complex parameters from the body of the request. However, only one parameter per action may be bound from body .

So you need to either

  1. Combine them into one class that just wraps / holds both parameters as properties - and have them bound from the body (as one object)
  2. Decide which to bind from the body, and which from the route or the query and add the attributes [FromRoute] or [FromQuery] to one, and [FromBody] to the other.

ApiExplorerSettings from System.Web.Http.Description will ignore the attributed action from a help page, or whatever else (maybe swagger)... but you will still get this exception - from problems at level of Model Binding

For me in the definition of the a new controller automatically add this prerequisite.
I removed it and it works

[Route("api/[controller]")]
[Apicontroller] //remove this line

My controller has some refactored code whose methods are marked public. Looks like either moving them out of the controller or marking private corrects this problem. Or attributing the pesky methods with [NonAction] might also be a choice as asked at asp.net Core mvc hide and exclude Web Api Controller Method

I received error "has more than one parameter that was specified ..." for having mention of [ApiController] on top of class and then inheriting class from APIController.

Corrected issue by inheriting the class from Controller.

[Authorize]
[Route("api/the")]
**[ApiController]**
public class TheController : **Controller**

I got this error by inheriting from BaseController instead of ControllerBase. It was a class from another library that is completely unrelated and I misremembered the name. The exception was a red herring for me.

I had this problem but solved it by declaring my method as private.

In my case, the problem was that in the controller I had public methods that are not endpoints. And the ASP.NET Core mapping for controllers treats all public methods as endpoints and tries to map the request model because it uses reflection.

Another possible solution is to nest the complex data types in a tuple:

[ApiExplorerSettings(IgnoreApi = true)]
public decimal CalculatePriceWithCampaign((BeverageCapacityCampaign campaign, BeverageCapacity capacity) data, int count = 1)
{
    switch (data.campaign.DiscountType)
    {
        case DiscountType.Fixed:
            return (data.capacity.CapacityPrice - data.campaign.DiscountValue) * count;
        case DiscountType.Percentage:
            return (data.capacity.CapacityPrice * count) * data.campaign.DiscountValue;
        default:
            return data.capacity.CapacityPrice;
    }
}

However, NSwag (Swagger) does not seems to be able to automatically parse this case because a non-valid example gets generated. NSwagStudio recognizes the case correctly and generates valid client code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM