From 4447cd17698160faadd51ff26c76b6faa79be069 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 29 Oct 2018 12:36:40 -0700 Subject: [PATCH] Respect ApiBehaviorOptions.SuppressInferBindingSourcesForParameters when specified Fixes https://github.com/aspnet/Mvc/issues/8657 --- .../InferParameterBindingInfoConvention.cs | 6 + ...InferParameterBindingInfoConventionTest.cs | 136 +++++++++++++++++- 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/InferParameterBindingInfoConvention.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/InferParameterBindingInfoConvention.cs index 8861263faf..5b1109fcc2 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/InferParameterBindingInfoConvention.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/InferParameterBindingInfoConvention.cs @@ -59,6 +59,12 @@ public void Apply(ControllerModel controller) internal void InferParameterBindingSources(ActionModel action) { + if (SuppressInferBindingSourcesForParameters) + { + // Do nothing. + return; + } + var inferredBindingSources = new BindingSource[action.Parameters.Count]; for (var i = 0; i < action.Parameters.Count; i++) diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModels/InferParameterBindingInfoConventionTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModels/InferParameterBindingInfoConventionTest.cs index 26da271e36..008a691154 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModels/InferParameterBindingInfoConventionTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModels/InferParameterBindingInfoConventionTest.cs @@ -156,6 +156,127 @@ public void OnProvidersExecuting_PreservesBindingInfo_WhenInferringFor_Parameter Assert.Equal("foo", bindingInfo.BinderModelName); } + [Fact] + public void Apply_InfersBindingSourceAndBinderModelName() + { + // Arrange + var actionName = nameof(TestController.PutModel); + var convention = GetConvention(); + var controller = GetControllerModel(typeof(TestController)); + + // Act + convention.Apply(controller); + + // Assert + var action = Assert.Single(controller.Actions, a => a.ActionName == actionName); + + Assert.Collection( + action.Parameters, + parameter => + { + Assert.Equal("id", parameter.Name); + var bindingInfo = parameter.BindingInfo; + Assert.NotNull(bindingInfo); + Assert.Same(BindingSource.Path, bindingInfo.BindingSource); + + Assert.Null(bindingInfo.BinderModelName); + }, + parameter => + { + Assert.Equal("model", parameter.Name); + var bindingInfo = parameter.BindingInfo; + Assert.NotNull(bindingInfo); + Assert.Same(BindingSource.Body, bindingInfo.BindingSource); + + Assert.Null(bindingInfo.BinderModelName); + }); + } + + [Fact] + public void Apply_DoesNotInferBindingSource_IfSuppressInferBindingSourcesForParametersIsSet() + { + // Arrange + var actionName = nameof(TestController.PutModel); + var convention = GetConvention(); + convention.SuppressInferBindingSourcesForParameters = true; + var controller = GetControllerModel(typeof(TestController)); + + // Act + convention.Apply(controller); + + // Assert + var action = Assert.Single(controller.Actions, a => a.ActionName == actionName); + + Assert.Collection( + action.Parameters, + parameter => + { + Assert.Equal("id", parameter.Name); + var bindingInfo = parameter.BindingInfo; + Assert.Null(bindingInfo); + }, + parameter => + { + Assert.Equal("model", parameter.Name); + var bindingInfo = parameter.BindingInfo; + Assert.Null(bindingInfo); + }); + } + + [Fact] + public void Apply_InfersParameterPrefix_IfSuppressInferBindingSourcesForParametersIsSet() + { + // Arrange + var actionName = nameof(TestController.GetByCoordinates); + var convention = GetConvention(); + convention.SuppressInferBindingSourcesForParameters = true; + var controller = GetControllerModel(typeof(TestController)); + + // Act + convention.Apply(controller); + + // Assert + var action = Assert.Single(controller.Actions, a => a.ActionName == actionName); + + var parameter = Assert.Single(action.Parameters); + var bindingInfo = parameter.BindingInfo; + Assert.NotNull(bindingInfo); + Assert.Equal(BindingSource.Query, bindingInfo.BindingSource); + Assert.Empty(bindingInfo.BinderModelName); + } + + [Fact] + public void Apply_InfersPropertyPrefix_IfSuppressInferBindingSourcesForParametersIsSet() + { + // Arrange + var convention = GetConvention(); + convention.SuppressInferBindingSourcesForParameters = true; + var controller = GetControllerModel(typeof(ControllerWithBoundProperty)); + + // Act + convention.Apply(controller); + + // Assert + Assert.Collection( + controller.ControllerProperties.OrderBy(p => p.Name), + property => + { + Assert.Equal(nameof(ControllerWithBoundProperty.Files), property.Name); + var bindingInfo = property.BindingInfo; + Assert.NotNull(bindingInfo); + Assert.Equal(BindingSource.Form, bindingInfo.BindingSource); + Assert.Null(bindingInfo.BinderModelName); // BindingSource is not greedy, BinderModelName should not be inferred. + }, + property => + { + Assert.Equal(nameof(ControllerWithBoundProperty.TestProperty), property.Name); + var bindingInfo = property.BindingInfo; + Assert.NotNull(bindingInfo); + Assert.Equal(BindingSource.Query, bindingInfo.BindingSource); + Assert.Empty(bindingInfo.BinderModelName); // BindingSource is greedy, BinderModelName should be inferred. + }); + } + [Fact] public void InferBindingSourceForParameter_ReturnsPath_IfParameterNameExistsInRouteAsSimpleToken() { @@ -725,7 +846,7 @@ public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileParamet { // Arrange var action = GetActionModel( - typeof(ParameterBindingController), + typeof(ParameterBindingController), nameof(ParameterBindingController.FromFormFormFileParameters), TestModelMetadataProvider.CreateDefaultProvider()); var convention = GetConvention(); @@ -758,8 +879,8 @@ public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileParamet { // Arrange var action = GetActionModel( - typeof(ParameterBindingController), - nameof(ParameterBindingController.FormFileParameters), + typeof(ParameterBindingController), + nameof(ParameterBindingController.FormFileParameters), TestModelMetadataProvider.CreateDefaultProvider()); var convention = GetConvention(); @@ -1070,5 +1191,14 @@ private class ParameterWithBindingInfo [HttpGet("test")] public IActionResult Action([ModelBinder(typeof(object))] Car car) => null; } + + private class TestController + { + [HttpPut("{id}")] + public IActionResult PutModel(int id, TestModel model) => null; + + [HttpPut("{id}")] + public IActionResult GetByCoordinates([FromQuery] GpsCoordinates coordinates) => null; + } } }