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:
parent
35597db277
commit
233140c33a
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue