In an API controller, if you have an action with both a complex model and a CancellationToken, MVC fails to infer the binding source:
Unable to unambiguously infer binding sources for parameters on 'System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[Models.UserModel]] Register(Controllers.RegisterUserModel, System.Threading.CancellationToken)'. More than one parameter may be inferred to bound from body.
It's easy enough to get around it by just setting SuppressInferBindingSourcesForParameters and slapping an explicit [FromBody] attribute on the model parameter, but this seems like a bug/oversight?
Also, BTW, it would be nice if you used TypeNameHelper for those kinds of error messages 馃槈
There's already a BindingSourceMetadataProvider defined for CancellationToken (and others), marking it as BindingSource.Special:
Shouldn't these be considered before trying to infer another binding source? Might be a stupid question, but I'm not super familiar with the model binding parts of the codebase 馃槤
Hmm. Looking at the ApiBehaviorApplicationModelProvider, I would've expected that the existing binding source would be reflected here:
But I guess there might be some ordering issues here?
Assigning to myself for tracking purposes only.
Might want to merge this with #7512. Cancellationtoken and existing Binding sources are listed there too.
Ah, I didn't realize that this had been filed before. Yeah, this will fix the first part of #7512, but there are other issues listed there that might need to be addressed as well.
This should be fixed with https://github.com/aspnet/Mvc/commit/c515cece8ed8a39b8163c3ba35024bcc79716ca0
In which version is this supposed to be fixed?
In 2.1-preview2-final with my repro from: https://github.com/aspnet/Mvc/issues/7512
I get for the Notworking example below (see repro)
[HttpPost]
[Route("NotWorking")]
public Task<IActionResult> Notworking(HelloWorld helloWorld, CancellationToken cancellationToken = default)
{
IActionResult okResult = new OkResult();
return Task.FromResult(okResult);
}
the following error message:
Unable to unambiguously infer binding sources for parameters on 'System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.IActionResult] Notworking(BodyBindingRepro.HelloWorld, System.Threading.CancellationToken)'. More than one parameter may be inferred to bound from body.
If I upgrade to the latest nugets from myget (2.1.0-rc1-30678) I get the following exception:
System.InvalidOperationException: Action 'BodyBindingRepro.TestController.Notworking (BodyBindingRepro)' 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:
HelloWorld helloWorld
CancellationToken cancellationToken
at Microsoft.AspNetCore.Mvc.Internal.ApiBehaviorApplicationModelProvider.InferParameterBindingSources(ActionModel actionModel)
at Microsoft.AspNetCore.Mvc.Internal.ApiBehaviorApplicationModelProvider.OnProvidersExecuting(ApplicationModelProviderContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.BuildModel()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.GetDescriptors()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionDescriptorProvider.OnProvidersExecuting(ActionDescriptorProviderContext context)
at Microsoft.AspNetCore.Mvc.Internal.ActionDescriptorCollectionProvider.UpdateCollection()
at Microsoft.AspNetCore.Mvc.Internal.ActionDescriptorCollectionProvider.get_ActionDescriptors()
at Microsoft.AspNetCore.Mvc.Internal.AttributeRoute.GetTreeRouter()
at Microsoft.AspNetCore.Mvc.Internal.AttributeRoute.RouteAsync(RouteContext context)
at Microsoft.AspNetCore.Routing.RouteCollection.<RouteAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.<Invoke>d__13.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.<ProcessRequests>d__186`1.MoveNext()
I thought we all agreed that CancellationToken is ignored?
@Tornhoof I'm not seeing it fail with the rc1 bits. Could you
a) Look at the obj\project.assets.json of the project and verify it's using Microsoft.AspNetCore.Mvc 2.1.0-rc1-30678? It'd be good to rule out restore issues.
b) zip up a repro and post it here if that's correct?
The assets look ok to me, it contains "Microsoft.AspNetCore/2.1.0-rc1-30678"
I zipped it up, the archive contains an output.txt which is the output log window, it shows loading those rc dlls and the exception from above:
BodyBindingRepro.zip
I removed the ref directory from the output, on my system it contains all those rc1 dlls, everything else is included.
What I did was:
To make sure it's not some sdk thing, I also installed the latest 2.1 rc sdk from dotnet/versions (which contains the version above: Output of dotnet --info
.NET Core SDK (gem盲脽 "global.json"):
Version: 2.1.300-rc1-008671
Commit: 04066cb5d8
Laufzeitumgebung:
OS Name: Windows
OS Version: 10.0.17134
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.1.300-rc1-008671\
Host (useful for support):
Version: 2.1.0-rc1-26426-04
Commit: b50a96ee38
.NET Core SDKs installed:
1.0.2 [C:\Program Files\dotnet\sdk]
1.0.3 [C:\Program Files\dotnet\sdk]
1.0.4 [C:\Program Files\dotnet\sdk]
1.1.0 [C:\Program Files\dotnet\sdk]
2.0.0 [C:\Program Files\dotnet\sdk]
2.0.2 [C:\Program Files\dotnet\sdk]
2.0.3 [C:\Program Files\dotnet\sdk]
2.1.104 [C:\Program Files\dotnet\sdk]
2.1.200-preview-007576 [C:\Program Files\dotnet\sdk]
2.1.200-preview-007589 [C:\Program Files\dotnet\sdk]
2.1.300-preview2-008530 [C:\Program Files\dotnet\sdk]
2.1.300-rc1-008671 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.0-preview2-final [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.0-rc1-30678 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.0-preview2-final [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.0-rc1-30678 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 1.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 1.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 1.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 1.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0-preview2-26406-04 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0-preview3-26416-01 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.0-rc1-26426-04 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
To install additional .NET Core runtimes or SDKs:
https://aka.ms/dotnet-download
You're missing .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); in your Startup:
var mvcBuilder = services.AddMvcCore(config =>
{
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
Thank you very much. It works now.
Still I find it weird that the new [ApiController] feature needs that one to work properly, but I understand it's a change to the 2.0 behaviour. Sorry for the trouble.
It's a bit unfortunate, but the right fix for the underlying issue affects all controllers, including non-ApiController ones. It's a change in behavior and hence guarded behind a compat switch.
Hello, I need help regarding Microsoft.AspNetCore.Mvc.Internal.ApiBehaviorApplicationModelProvider.InferParameterBindingSources(ActionModel actionModel).
Currently, I have this situation:

What am I doing wrong?
What am I doing wrong?
Did you annotate your controller with the [ApiController] Attribute?
Yes, please take a look:

Your method has multiple complex types (atleast from the type names) as parameters, as the error message tells you, you can only have on in the body.
You need to decide which one and pass everything else in as [FromQuery] or remove them.
If it is a new API and not an existing one, I highly recommend rethinking the behaviour of passing multiple complex into it.
Hi, it looks like you are posting on a closed issue/PR/commit!
We're very likely to lose track of your bug/feedback/question unless you:
Thanks!
Most helpful comment
You're missing
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);in your Startup: