Allow IFormFile parameters annotated with [FromForm] to be correctly … (#8452)

* Allow IFormFile parameters annotated with [FromForm] to be correctly bound in ApiControllers

Fixes #8311
This commit is contained in:
Pranav K 2018-09-14 09:06:32 -07:00 committed by GitHub
parent 35597db277
commit 233140c33a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 2 deletions

View File

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Template;
@ -112,7 +114,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
if (property.BindingInfo != null && if (property.BindingInfo != null &&
property.BindingInfo.BinderModelName == null && property.BindingInfo.BinderModelName == null &&
property.BindingInfo.BindingSource != null && property.BindingInfo.BindingSource != null &&
!property.BindingInfo.BindingSource.IsGreedy) !property.BindingInfo.BindingSource.IsGreedy &&
!IsFormFile(property.ParameterType))
{ {
var metadata = _modelMetadataProvider.GetMetadataForProperty( var metadata = _modelMetadataProvider.GetMetadataForProperty(
controllerModel.ControllerType, controllerModel.ControllerType,
@ -133,6 +136,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
if (bindingInfo?.BindingSource != null && if (bindingInfo?.BindingSource != null &&
bindingInfo.BinderModelName == null && bindingInfo.BinderModelName == null &&
!bindingInfo.BindingSource.IsGreedy && !bindingInfo.BindingSource.IsGreedy &&
!IsFormFile(parameter.ParameterType) &&
IsComplexTypeParameter(parameter)) IsComplexTypeParameter(parameter))
{ {
parameter.BindingInfo.BinderModelName = string.Empty; parameter.BindingInfo.BinderModelName = string.Empty;
@ -166,5 +170,11 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
.GetMetadataForType(parameter.ParameterInfo.ParameterType); .GetMetadataForType(parameter.ParameterInfo.ParameterType);
return metadata.IsComplexType && !metadata.IsCollectionType; return metadata.IsComplexType && !metadata.IsCollectionType;
} }
private static bool IsFormFile(Type parameterType)
{
return typeof(IFormFile).IsAssignableFrom(parameterType) ||
typeof(IEnumerable<IFormFile>).IsAssignableFrom(parameterType);
}
} }
} }

View File

@ -686,7 +686,7 @@ Environment.NewLine + "int b";
convention.InferBoundPropertyModelPrefixes(controller); convention.InferBoundPropertyModelPrefixes(controller);
// Assert // Assert
var property = Assert.Single(controller.ControllerProperties); var property = Assert.Single(controller.ControllerProperties, p => p.Name == nameof(ControllerWithBoundProperty.TestProperty));
Assert.Equal(string.Empty, property.BindingInfo.BinderModelName); Assert.Equal(string.Empty, property.BindingInfo.BinderModelName);
} }
@ -720,6 +720,87 @@ Environment.NewLine + "int b";
Assert.Equal(string.Empty, parameter.BindingInfo.BinderModelName); Assert.Equal(string.Empty, parameter.BindingInfo.BinderModelName);
} }
[Fact]
public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileParametersAnnotatedWithFromForm()
{
// Arrange
var action = GetActionModel(
typeof(ParameterBindingController),
nameof(ParameterBindingController.FromFormFormFileParameters),
TestModelMetadataProvider.CreateDefaultProvider());
var convention = GetConvention();
// Act
convention.InferParameterModelPrefixes(action);
// Assert
Assert.Collection(
action.Parameters,
parameter =>
{
Assert.Equal("p1", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
},
parameter =>
{
Assert.Equal("p2", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
},
parameter =>
{
Assert.Equal("p3", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
});
}
[Fact]
public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileParameters()
{
// Arrange
var action = GetActionModel(
typeof(ParameterBindingController),
nameof(ParameterBindingController.FormFileParameters),
TestModelMetadataProvider.CreateDefaultProvider());
var convention = GetConvention();
// Act
convention.InferParameterModelPrefixes(action);
// Assert
Assert.Collection(
action.Parameters,
parameter =>
{
Assert.Equal("p1", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
},
parameter =>
{
Assert.Equal("p2", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
},
parameter =>
{
Assert.Equal("p3", parameter.Name);
Assert.Null(parameter.BindingInfo.BinderModelName);
});
}
[Fact]
public void InferBoundPropertyModelPrefixes_DoesNotSetModelPrefix_ForFormFileCollectionPropertiesAnnotatedWithFromForm()
{
// Arrange
var controller = GetControllerModel(typeof(ControllerWithBoundProperty));
var convention = GetConvention();
// Act
convention.InferBoundPropertyModelPrefixes(controller);
// Assert
var parameter = Assert.Single(controller.ControllerProperties, p => p.Name == nameof(ControllerWithBoundProperty.Files));
Assert.Null(parameter.BindingInfo.BinderModelName);
}
private static InferParameterBindingInfoConvention GetConvention( private static InferParameterBindingInfoConvention GetConvention(
IModelMetadataProvider modelMetadataProvider = null) IModelMetadataProvider modelMetadataProvider = null)
{ {
@ -861,6 +942,10 @@ Environment.NewLine + "int b";
[HttpGet] [HttpGet]
public IActionResult ParameterWithRequestPredicateProvider([CustomRequestPredicateAndPropertyFilterProvider] int value) => null; public IActionResult ParameterWithRequestPredicateProvider([CustomRequestPredicateAndPropertyFilterProvider] int value) => null;
public IActionResult FromFormFormFileParameters([FromForm] IFormFile p1, [FromForm] IFormFile[] p2, [FromForm] IFormFileCollection p3) => null;
public IActionResult FormFileParameters(IFormFile p1, IFormFile[] p2, IFormFileCollection p3) => null;
} }
[ApiController] [ApiController]
@ -955,6 +1040,9 @@ Environment.NewLine + "int b";
[FromQuery] [FromQuery]
public TestModel TestProperty { get; set; } public TestModel TestProperty { get; set; }
[FromForm]
public IList<IFormFile> Files { get; set; }
public IActionResult SomeAction([FromQuery] TestModel test) => null; public IActionResult SomeAction([FromQuery] TestModel test) => null;
} }