Merge pull request #7590 from aspnet/release/2.1

Release/2.1
This commit is contained in:
Pranav K 2018-04-02 09:49:14 -07:00 committed by GitHub
commit c7559e1ff4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 787 additions and 219 deletions

View File

@ -65,6 +65,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// <summary>
/// Constructs a new instance of <see cref="BindingInfo"/> from the given <paramref name="attributes"/>.
/// <para>
/// This overload does not account for <see cref="BindingInfo"/> specified via <see cref="ModelMetadata"/>. Consider using
/// <see cref="GetBindingInfo(IEnumerable{object}, ModelMetadata)"/> overload, or <see cref="TryApplyBindingInfo(ModelMetadata)"/>
/// on the result of this method to to get a more accurate <see cref="BindingInfo"/> instance.
/// </para>
/// </summary>
/// <param name="attributes">A collection of attributes which are used to construct <see cref="BindingInfo"/>
/// </param>
@ -134,6 +139,81 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return isBindingInfoPresent ? bindingInfo : null;
}
/// <summary>
/// Constructs a new instance of <see cref="BindingInfo"/> from the given <paramref name="attributes"/> and <paramref name="modelMetadata"/>.
/// </summary>
/// <param name="attributes">A collection of attributes which are used to construct <see cref="BindingInfo"/>.</param>
/// <param name="modelMetadata">The <see cref="ModelMetadata"/>.</param>
/// <returns>A new instance of <see cref="BindingInfo"/> if any binding metadata was discovered; otherwise or <see langword="null"/>.</returns>
public static BindingInfo GetBindingInfo(IEnumerable<object> attributes, ModelMetadata modelMetadata)
{
if (attributes == null)
{
throw new ArgumentNullException(nameof(attributes));
}
if (modelMetadata == null)
{
throw new ArgumentNullException(nameof(modelMetadata));
}
var bindingInfo = GetBindingInfo(attributes);
var isBindingInfoPresent = bindingInfo != null;
if (bindingInfo == null)
{
bindingInfo = new BindingInfo();
}
isBindingInfoPresent |= bindingInfo.TryApplyBindingInfo(modelMetadata);
return isBindingInfoPresent ? bindingInfo : null;
}
/// <summary>
/// Applies binding metadata from the specified <paramref name="modelMetadata"/>.
/// <para>
/// Uses values from <paramref name="modelMetadata"/> if no value is already available.
/// </para>
/// </summary>
/// <param name="modelMetadata">The <see cref="ModelMetadata"/>.</param>
/// <returns><see langword="true"/> if any binding metadata from <paramref name="modelMetadata"/> was applied;
/// <see langword="false"/> otherwise.</returns>
public bool TryApplyBindingInfo(ModelMetadata modelMetadata)
{
if (modelMetadata == null)
{
throw new ArgumentNullException(nameof(modelMetadata));
}
var isBindingInfoPresent = false;
if (BinderModelName == null && modelMetadata.BinderModelName != null)
{
isBindingInfoPresent = true;
BinderModelName = modelMetadata.BinderModelName;
}
if (BinderType == null && modelMetadata.BinderType != null)
{
isBindingInfoPresent = true;
BinderType = modelMetadata.BinderType;
}
if (BindingSource == null && modelMetadata.BindingSource != null)
{
isBindingInfoPresent = true;
BindingSource = modelMetadata.BindingSource;
}
if (PropertyFilterProvider == null && modelMetadata.PropertyFilterProvider != null)
{
isBindingInfoPresent = true;
PropertyFilterProvider = modelMetadata.PropertyFilterProvider;
}
return isBindingInfoPresent;
}
private class CompositePropertyFilterProvider : IPropertyFilterProvider
{
private readonly IEnumerable<IPropertyFilterProvider> _providers;

View File

@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
isFromRequest: false);
/// <summary>
/// A <see cref="BindingSource"/> for <see cref="IFormFile"/> and <see cref="IFormCollection"/>.
/// A <see cref="BindingSource"/> for <see cref="IFormFile"/>, <see cref="IFormCollection"/>, and <see cref="IFormFileCollection"/>.
/// </summary>
public static readonly BindingSource FormFile = new BindingSource(
"FormFile",

View File

@ -618,8 +618,8 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
return new ApiParameterDescriptionContext
{
ModelMetadata = metadata,
BinderModelName = bindingInfo?.BinderModelName ?? metadata.BinderModelName,
BindingSource = bindingInfo?.BindingSource ?? metadata.BindingSource,
BinderModelName = bindingInfo?.BinderModelName,
BindingSource = bindingInfo?.BindingSource,
PropertyName = propertyName ?? metadata.Name,
};
}
@ -716,9 +716,11 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
{
var propertyMetadata = modelMetadata.Properties[i];
var key = new PropertyKey(propertyMetadata, source);
var bindingInfo = BindingInfo.GetBindingInfo(Enumerable.Empty<object>(), propertyMetadata);
var propertyContext = ApiParameterDescriptionContext.GetContext(
propertyMetadata,
bindingInfo: null,
bindingInfo: bindingInfo,
propertyName: null);
if (Visited.Add(key))

View File

@ -139,7 +139,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
actionModel.Filters.Add(_modelStateInvalidFilter);
}
private void InferParameterBindingSources(ActionModel actionModel)
// Internal for unit testing
internal void InferParameterBindingSources(ActionModel actionModel)
{
if (_modelMetadataProvider == null || _apiBehaviorOptions.SuppressInferBindingSourcesForParameters)
{

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
@ -19,11 +18,15 @@ namespace Microsoft.AspNetCore.Mvc.Internal
{
public class DefaultApplicationModelProvider : IApplicationModelProvider
{
private readonly ICollection<IFilterMetadata> _globalFilters;
private readonly MvcOptions _mvcOptions;
private readonly IModelMetadataProvider _modelMetadataProvider;
public DefaultApplicationModelProvider(IOptions<MvcOptions> mvcOptionsAccessor)
public DefaultApplicationModelProvider(
IOptions<MvcOptions> mvcOptionsAccessor,
IModelMetadataProvider modelMetadataProvider)
{
_globalFilters = mvcOptionsAccessor.Value.Filters;
_mvcOptions = mvcOptionsAccessor.Value;
_modelMetadataProvider = modelMetadataProvider;
}
/// <inheritdoc />
@ -37,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
throw new ArgumentNullException(nameof(context));
}
foreach (var filter in _globalFilters)
foreach (var filter in _mvcOptions.Filters)
{
context.Result.Filters.Add(filter);
}
@ -118,9 +121,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
do
{
routeAttributes = currentTypeInfo
.GetCustomAttributes(inherit: false)
.OfType<IRouteTemplateProvider>()
.ToArray();
.GetCustomAttributes(inherit: false)
.OfType<IRouteTemplateProvider>()
.ToArray();
if (routeAttributes.Length > 0)
{
@ -213,24 +216,17 @@ namespace Microsoft.AspNetCore.Mvc.Internal
throw new ArgumentNullException(nameof(propertyInfo));
}
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
// is needed to so that the result of ToArray() is object
var attributes = propertyInfo.GetCustomAttributes(inherit: true);
var propertyModel = new PropertyModel(propertyInfo, attributes);
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
if (bindingInfo != null)
{
propertyModel.BindingInfo = bindingInfo;
}
else if (IsFormFileType(propertyInfo.PropertyType))
{
propertyModel.BindingInfo = new BindingInfo
{
BindingSource = BindingSource.FormFile,
};
}
propertyModel.PropertyName = propertyInfo.Name;
var modelMetadata = _modelMetadataProvider.GetMetadataForProperty(propertyInfo.DeclaringType, propertyInfo.Name);
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
var propertyModel = new PropertyModel(propertyInfo, attributes)
{
PropertyName = propertyInfo.Name,
BindingInfo = bindingInfo,
};
return propertyModel;
}
@ -433,25 +429,25 @@ namespace Microsoft.AspNetCore.Mvc.Internal
throw new ArgumentNullException(nameof(parameterInfo));
}
// CoreCLR returns IEnumerable<Attribute> from GetCustomAttributes - the OfType<object>
// is needed to so that the result of ToArray() is object
var attributes = parameterInfo.GetCustomAttributes(inherit: true);
var parameterModel = new ParameterModel(parameterInfo, attributes);
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
if (bindingInfo != null)
BindingInfo bindingInfo;
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
{
parameterModel.BindingInfo = bindingInfo;
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
}
else if (IsFormFileType(parameterInfo.ParameterType))
else
{
parameterModel.BindingInfo = new BindingInfo
{
BindingSource = BindingSource.FormFile,
};
// GetMetadataForParameter should only be used if the user has opted in to the 2.1 behavior.
bindingInfo = BindingInfo.GetBindingInfo(attributes);
}
parameterModel.ParameterName = parameterInfo.Name;
var parameterModel = new ParameterModel(parameterInfo, attributes)
{
ParameterName = parameterInfo.Name,
BindingInfo = bindingInfo,
};
return parameterModel;
}
@ -670,12 +666,5 @@ namespace Microsoft.AspNetCore.Mvc.Internal
list.Add(item);
}
}
private static bool IsFormFileType(Type parameterType)
{
return parameterType == typeof(IFormFile) ||
parameterType == typeof(IFormFileCollection) ||
typeof(IEnumerable<IFormFile>).IsAssignableFrom(parameterType);
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.Http;
@ -76,28 +77,34 @@ namespace Microsoft.AspNetCore.Mvc.Internal
options.ValueProviderFactories.Add(new JQueryFormValueProviderFactory());
// Set up metadata providers
// Don't bind the Type class by default as it's expensive. A user can override this behavior
// by altering the collection of providers.
options.ModelMetadataDetailsProviders.Add(new ExcludeBindingMetadataProvider(typeof(Type)));
options.ModelMetadataDetailsProviders.Add(new DefaultBindingMetadataProvider());
options.ModelMetadataDetailsProviders.Add(new DefaultValidationMetadataProvider());
options.ModelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(CancellationToken), BindingSource.Special));
options.ModelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormFile), BindingSource.FormFile));
options.ModelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormCollection), BindingSource.FormFile));
ConfigureAdditionalModelMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
// Set up validators
options.ModelValidatorProviders.Add(new DefaultModelValidatorProvider());
}
internal static void ConfigureAdditionalModelMetadataDetailsProvider(IList<IMetadataDetailsProvider> modelMetadataDetailsProviders)
{
// Don't bind the Type class by default as it's expensive. A user can override this behavior
// by altering the collection of providers.
modelMetadataDetailsProviders.Add(new ExcludeBindingMetadataProvider(typeof(Type)));
modelMetadataDetailsProviders.Add(new DefaultBindingMetadataProvider());
modelMetadataDetailsProviders.Add(new DefaultValidationMetadataProvider());
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(CancellationToken), BindingSource.Special));
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormFile), BindingSource.FormFile));
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormCollection), BindingSource.FormFile));
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormFileCollection), BindingSource.FormFile));
// Add types to be excluded from Validation
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Type)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Uri)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(CancellationToken)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IFormFile)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IFormCollection)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Type)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Uri)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(CancellationToken)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IFormFile)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IFormCollection)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(IFormFileCollection)));
modelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(Stream)));
}
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Options;

View File

@ -233,14 +233,18 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
_factory = factory;
Metadata = factoryContext.Metadata;
BindingInfo = new BindingInfo
BindingInfo bindingInfo;
if (factoryContext.BindingInfo != null)
{
BinderModelName = factoryContext.BindingInfo?.BinderModelName ?? Metadata.BinderModelName,
BinderType = factoryContext.BindingInfo?.BinderType ?? Metadata.BinderType,
BindingSource = factoryContext.BindingInfo?.BindingSource ?? Metadata.BindingSource,
PropertyFilterProvider =
factoryContext.BindingInfo?.PropertyFilterProvider ?? Metadata.PropertyFilterProvider,
};
bindingInfo = new BindingInfo(factoryContext.BindingInfo);
}
else
{
bindingInfo = new BindingInfo();
}
bindingInfo.TryApplyBindingInfo(Metadata);
BindingInfo = bindingInfo;
MetadataProvider = _factory._metadataProvider;
Visited = new Dictionary<Key, IModelBinder>();

View File

@ -310,10 +310,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
// This is to avoid adding validation errors for an 'empty' prefix when a simple
// type fails to bind. The fix for #7503 uncovered this issue, and was likely the
// original problem being worked around that regressed #7503.
string modelName = modelBindingContext.ModelName;
var modelName = modelBindingContext.ModelName;
if (string.IsNullOrEmpty(modelBindingContext.ModelName) &&
(parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName) == null)
parameter.BindingInfo?.BinderModelName == null)
{
// If we get here then this is a fallback case. The model name wasn't explicitly set
// and we ended up with an empty prefix.

View File

@ -5,5 +5,6 @@ using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Formatters;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Core.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.TestCommon, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: TypeForwardedTo(typeof(InputFormatterException))]

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
{
@ -17,6 +18,16 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private const string ModelPropertyName = "Model";
private readonly PageHandlerPageFilter _pageHandlerPageFilter = new PageHandlerPageFilter();
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
private readonly IModelMetadataProvider _modelMetadataProvider;
private readonly MvcOptions _options;
public DefaultPageApplicationModelProvider(
IModelMetadataProvider modelMetadataProvider,
IOptions<MvcOptions> options)
{
_modelMetadataProvider = modelMetadataProvider;
_options = options.Value;
}
/// <inheritdoc />
public int Order => -1000;
@ -217,9 +228,22 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
throw new ArgumentNullException(nameof(parameter));
}
return new PageParameterModel(parameter, parameter.GetCustomAttributes(inherit: true))
var attributes = parameter.GetCustomAttributes(inherit: true);
BindingInfo bindingInfo;
if (_options.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
{
BindingInfo = BindingInfo.GetBindingInfo(parameter.GetCustomAttributes()),
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
}
else
{
bindingInfo = BindingInfo.GetBindingInfo(attributes);
}
return new PageParameterModel(parameter, attributes)
{
BindingInfo = bindingInfo,
ParameterName = parameter.Name,
};
}
@ -237,12 +261,19 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
}
var propertyAttributes = property.GetCustomAttributes(inherit: true);
var handlerAttributes = property.DeclaringType.GetCustomAttributes(inherit: true);
// Look for binding info on the handler if nothing is specified on the property.
// This allows BindProperty attributes on handlers to apply to properties.
var bindingInfo = BindingInfo.GetBindingInfo(propertyAttributes) ??
BindingInfo.GetBindingInfo(handlerAttributes);
var propertyMetadata = _modelMetadataProvider.GetMetadataForProperty(property.DeclaringType, property.Name);
var bindingInfo = BindingInfo.GetBindingInfo(propertyAttributes, propertyMetadata);
if (bindingInfo == null)
{
// Look for binding info on the handler if nothing is specified on the property.
// This allows BindProperty attributes on handlers to apply to properties.
var handlerType = property.DeclaringType;
var handlerAttributes = handlerType.GetCustomAttributes(inherit: true);
var handlerMetadata = _modelMetadataProvider.GetMetadataForType(property.DeclaringType);
bindingInfo = BindingInfo.GetBindingInfo(handlerAttributes, handlerMetadata);
}
var model = new PagePropertyModel(property, propertyAttributes)
{

View File

@ -6,6 +6,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc\Microsoft.AspNetCore.Mvc.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Mvc.TestCommon\Microsoft.AspNetCore.Mvc.TestCommon.csproj" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
</ItemGroup>

View File

@ -0,0 +1,197 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
public class BindingInfoTest
{
[Fact]
public void GetBindingInfo_WithAttributes_ConstructsBindingInfo()
{
// Arrange
var attributes = new object[]
{
new FromQueryAttribute { Name = "Test" },
};
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same("Test", bindingInfo.BinderModelName);
Assert.Same(BindingSource.Query, bindingInfo.BindingSource);
}
[Fact]
public void GetBindingInfo_ReadsPropertyPredicateProvider()
{
// Arrange
var bindAttribute = new BindAttribute(include: "SomeProperty");
var attributes = new object[]
{
bindAttribute,
};
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(bindAttribute, bindingInfo.PropertyFilterProvider);
}
[Fact]
public void GetBindingInfo_ReadsRequestPredicateProvider()
{
// Arrange
var attributes = new object[]
{
new BindPropertyAttribute { Name = "PropertyPrefix", SupportsGet = true, },
};
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same("PropertyPrefix", bindingInfo.BinderModelName);
Assert.NotNull(bindingInfo.RequestPredicate);
}
[Fact]
public void GetBindingInfo_ReturnsNull_IfNoBindingAttributesArePresent()
{
// Arrange
var attributes = new object[] { new ControllerAttribute(), new BindNeverAttribute(), };
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes);
// Assert
Assert.Null(bindingInfo);
}
[Fact]
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesValuesFromBindingInfo_IfAttributesPresent()
{
// Arrange
var attributes = new object[]
{
new ModelBinderAttribute { BinderType = typeof(object), Name = "Test" },
};
var modelType = typeof(Guid);
var provider = new TestModelMetadataProvider();
provider.ForType(modelType).BindingDetails(metadata =>
{
metadata.BindingSource = BindingSource.Special;
metadata.BinderType = typeof(string);
metadata.BinderModelName = "Different";
});
var modelMetadata = provider.GetMetadataForType(modelType);
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(typeof(object), bindingInfo.BinderType);
Assert.Same("Test", bindingInfo.BinderModelName);
}
[Fact]
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderNameFromModelMetadata_WhenNotFoundViaAttributes()
{
// Arrange
var attributes = new object[] { new ModelBinderAttribute(typeof(object)), new ControllerAttribute(), new BindNeverAttribute(), };
var modelType = typeof(Guid);
var provider = new TestModelMetadataProvider();
provider.ForType(modelType).BindingDetails(metadata =>
{
metadata.BindingSource = BindingSource.Special;
metadata.BinderType = typeof(string);
metadata.BinderModelName = "Different";
});
var modelMetadata = provider.GetMetadataForType(modelType);
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(typeof(object), bindingInfo.BinderType);
Assert.Same("Different", bindingInfo.BinderModelName);
Assert.Same(BindingSource.Custom, bindingInfo.BindingSource);
}
[Fact]
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesModelBinderFromModelMetadata_WhenNotFoundViaAttributes()
{
// Arrange
var attributes = new object[] { new ControllerAttribute(), new BindNeverAttribute(), };
var modelType = typeof(Guid);
var provider = new TestModelMetadataProvider();
provider.ForType(modelType).BindingDetails(metadata =>
{
metadata.BinderType = typeof(string);
});
var modelMetadata = provider.GetMetadataForType(modelType);
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(typeof(string), bindingInfo.BinderType);
}
[Fact]
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderSourceFromModelMetadata_WhenNotFoundViaAttributes()
{
// Arrange
var attributes = new object[] { new BindPropertyAttribute(), new ControllerAttribute(), new BindNeverAttribute(), };
var modelType = typeof(Guid);
var provider = new TestModelMetadataProvider();
provider.ForType(modelType).BindingDetails(metadata =>
{
metadata.BindingSource = BindingSource.Services;
});
var modelMetadata = provider.GetMetadataForType(modelType);
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(BindingSource.Services, bindingInfo.BindingSource);
}
[Fact]
public void GetBindingInfo_WithAttributesAndModelMetadata_UsesPropertyPredicateProviderFromModelMetadata_WhenNotFoundViaAttributes()
{
// Arrange
var attributes = new object[] { new ModelBinderAttribute(typeof(object)), new ControllerAttribute(), new BindNeverAttribute(), };
var modelAttributes = new ModelAttributes(Enumerable.Empty<object>(), null, null);
var propertyFilterProvider = Mock.Of<IPropertyFilterProvider>();
var modelType = typeof(Guid);
var provider = new TestModelMetadataProvider();
provider.ForType(modelType).BindingDetails(metadata =>
{
metadata.PropertyFilterProvider = propertyFilterProvider;
});
var modelMetadata = provider.GetMetadataForType(modelType);
// Act
var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
// Assert
Assert.NotNull(bindingInfo);
Assert.Same(propertyFilterProvider, bindingInfo.PropertyFilterProvider);
}
}
}

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@ -790,7 +791,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
var manager = GetApplicationManager(controllerTypes);
var modelProvider = new DefaultApplicationModelProvider(options);
var modelProvider = new DefaultApplicationModelProvider(options, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,
@ -964,8 +965,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
foreach (var item in context.Results)
{
var marker = item.Metadata as BooleanConstraintMarker;
if (marker != null)
if (item.Metadata is BooleanConstraintMarker marker)
{
Assert.Null(item.Constraint);
item.Constraint = new BooleanConstraint() { Pass = marker.Pass };

View File

@ -5,6 +5,7 @@ using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Infrastructure;
@ -383,6 +384,31 @@ namespace Microsoft.AspNetCore.Mvc.Internal
Assert.Same(BindingSource.Body, result);
}
[Fact]
public void InferParameterBindingSources_SetsCorrectBindingSourceForComplexTypesWithCancellationToken()
{
// Arrange
var actionName = nameof(ParameterBindingController.ComplexTypeModelWithCancellationToken);
// Use the default set of ModelMetadataProviders so we get metadata details for CancellationToken.
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var context = GetContext(typeof(ParameterBindingController), modelMetadataProvider);
var controllerModel = Assert.Single(context.Result.Controllers);
var actionModel = Assert.Single(controllerModel.Actions, m => m.ActionName == actionName);
var provider = GetProvider();
// Act
provider.InferParameterBindingSources(actionModel);
// Assert
var model = GetParameterModel<TestModel>(actionModel);
Assert.Same(BindingSource.Body, model.BindingInfo.BindingSource);
var cancellationToken = GetParameterModel<CancellationToken>(actionModel);
Assert.Same(BindingSource.Special, cancellationToken.BindingInfo.BindingSource);
}
[Fact]
public void InferBindingSourceForParameter_ReturnsBodyForSimpleTypes()
{
@ -503,16 +529,21 @@ namespace Microsoft.AspNetCore.Mvc.Internal
};
var optionsAccessor = Options.Create(options);
modelMetadataProvider = modelMetadataProvider ?? new TestModelMetadataProvider();
var loggerFactory = NullLoggerFactory.Instance;
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
return new ApiBehaviorApplicationModelProvider(optionsAccessor, modelMetadataProvider, loggerFactory);
}
private static ApplicationModelProviderContext GetContext(Type type)
private static ApplicationModelProviderContext GetContext(
Type type,
IModelMetadataProvider modelMetadataProvider = null)
{
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
new DefaultApplicationModelProvider(Options.Create(new MvcOptions())).OnProvidersExecuting(context);
var mvcOptions = Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true });
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
var provider = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
provider.OnProvidersExecuting(context);
return context;
}
@ -535,6 +566,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return Assert.Single(action.Parameters);
}
private static ParameterModel GetParameterModel<T>(ActionModel action)
{
return Assert.Single(action.Parameters.Where(x => typeof(T).IsAssignableFrom(x.ParameterType)));
}
[ApiController]
[Route("TestApi")]
private class TestApiController : Controller
@ -612,6 +648,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
[HttpPost]
[Consumes("application/json")]
public IActionResult ActionWithConsumesAttribute([FromForm] string parameter) => null;
[HttpPut("cancellation")]
public IActionResult ComplexTypeModelWithCancellationToken(TestModel model, CancellationToken cancellationToken) => null;
}
[ApiController]

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -22,10 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
{
// Arrange
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())));
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(AccountController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var controllerType = typeof(AccountController);
var context = CreateProviderContext(controllerType);
// Act
provider.OnProvidersExecuting(context);
@ -44,10 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
options.Value.AddPolicy("Derived", policy => policy.RequireClaim("Derived"));
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(options));
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(DerivedController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = CreateProviderContext(typeof(DerivedController));
// Act
provider.OnProvidersExecuting(context);
@ -71,10 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
{
// Arrange
var provider = new AuthorizationApplicationModelProvider(new DefaultAuthorizationPolicyProvider(Options.Create(new AuthorizationOptions())));
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(AnonymousController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = CreateProviderContext(typeof(AnonymousController));
// Act
provider.OnProvidersExecuting(context);
@ -100,10 +93,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var policyProvider = new DefaultAuthorizationPolicyProvider(authOptions);
var provider = new AuthorizationApplicationModelProvider(policyProvider);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = CreateProviderContext(typeof(BaseController));
// Act
var action = GetBaseControllerActionModel(provider, defaultProvider);
var action = GetBaseControllerActionModel(provider);
// Assert
var authorizationFilter = Assert.IsType<AuthorizeFilter>(Assert.Single(action.Filters));
@ -128,10 +121,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
.Verifiable();
var provider = new AuthorizationApplicationModelProvider(authorizationPolicyProviderMock.Object);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
// Act
var action = GetBaseControllerActionModel(provider, defaultProvider);
var action = GetBaseControllerActionModel(provider);
// Assert
var actionFilter = Assert.IsType<AuthorizeFilter>(Assert.Single(action.Filters));
@ -148,10 +140,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
new DefaultAuthorizationPolicyProvider(
Options.Create(new AuthorizationOptions())
));
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(NoAuthController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = CreateProviderContext(typeof(NoAuthController));
// Act
provider.OnProvidersExecuting(context);
@ -163,16 +152,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
Assert.Empty(action.Filters);
}
private ActionModel GetBaseControllerActionModel(
IApplicationModelProvider authorizationApplicationModelProvider,
IApplicationModelProvider applicationModelProvider)
private ActionModel GetBaseControllerActionModel(AuthorizationApplicationModelProvider authorizationApplicationModelProvider)
{
var context = new ApplicationModelProviderContext(new[] { typeof(BaseController).GetTypeInfo() });
applicationModelProvider.OnProvidersExecuting(context);
var authorizeData = new List<IAuthorizeData>
{
new AuthorizeAttribute("POLICY")
};
var context = CreateProviderContext(typeof(BaseController));
authorizationApplicationModelProvider.OnProvidersExecuting(context);
@ -183,6 +165,17 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return action;
}
private static ApplicationModelProviderContext CreateProviderContext(Type controllerType)
{
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { controllerType.GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
return context;
}
private class BaseController
{
[Authorize(Policy = "Base")]

View File

@ -709,7 +709,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var manager = GetApplicationManager(new[] { controllerTypeInfo });
var options = Options.Create(new MvcOptions());
options.Value.Conventions.Add(new TestRoutingConvention());
var modelProvider = new DefaultApplicationModelProvider(options);
var modelProvider = new DefaultApplicationModelProvider(options, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,
new[] { modelProvider },
@ -1397,7 +1397,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var manager = GetApplicationManager(new[] { controllerTypeInfo });
var modelProvider = new DefaultApplicationModelProvider(options);
var modelProvider = new DefaultApplicationModelProvider(options, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,
@ -1413,7 +1413,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var options = Options.Create(new MvcOptions());
var manager = GetApplicationManager(controllerTypeInfos);
var modelProvider = new DefaultApplicationModelProvider(options);
var modelProvider = new DefaultApplicationModelProvider(options, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,
@ -1432,7 +1432,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
var manager = GetApplicationManager(new[] { controllerTypeInfo });
var modelProvider = new DefaultApplicationModelProvider(options);
var modelProvider = new DefaultApplicationModelProvider(options, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Options;
using Xunit;
@ -74,6 +75,49 @@ namespace Microsoft.AspNetCore.Mvc.Internal
});
}
[Fact]
public void OnProvidersExecuting_ReadsBindingSourceForPropertiesFromModelMetadata()
{
// Arrange
var detailsProvider = new BindingSourceMetadataProvider(typeof(string), BindingSource.Services);
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
var provider = new TestApplicationModelProvider(Options.Create(new MvcOptions()), modelMetadataProvider);
var context = new ApplicationModelProviderContext(new[] { typeInfo });
// Act
provider.OnProvidersExecuting(context);
// Assert
var controllerModel = Assert.Single(context.Result.Controllers);
Assert.Collection(
controllerModel.ControllerProperties.OrderBy(p => p.PropertyName),
property =>
{
Assert.Equal(nameof(ModelBinderController.Bound), property.PropertyName);
Assert.Equal(BindingSource.Query, property.BindingInfo.BindingSource);
Assert.Same(controllerModel, property.Controller);
var attribute = Assert.Single(property.Attributes);
Assert.IsType<FromQueryAttribute>(attribute);
},
property =>
{
Assert.Equal(nameof(ModelBinderController.FormFile), property.PropertyName);
Assert.Equal(BindingSource.FormFile, property.BindingInfo.BindingSource);
Assert.Same(controllerModel, property.Controller);
Assert.Empty(property.Attributes);
},
property =>
{
Assert.Equal(nameof(ModelBinderController.Unbound), property.PropertyName);
Assert.Equal(BindingSource.Services, property.BindingInfo.BindingSource);
Assert.Same(controllerModel, property.Controller);
});
}
[Fact]
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters()
{
@ -88,7 +132,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
// Assert
var controllerModel = Assert.Single(context.Result.Controllers);
var action = Assert.Single(controllerModel.Actions);
var action = Assert.Single(controllerModel.Actions, a => a.ActionMethod.Name == nameof(ModelBinderController.PostAction));
Assert.Collection(
action.Parameters,
parameter =>
@ -116,6 +160,107 @@ namespace Microsoft.AspNetCore.Mvc.Internal
});
}
[Fact]
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_WithLegacyValidationBehavior()
{
// Arrange
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var options = Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false });
var builder = new TestApplicationModelProvider(options, modelMetadataProvider);
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
var context = new ApplicationModelProviderContext(new[] { typeInfo });
// Act
builder.OnProvidersExecuting(context);
// Assert
var controllerModel = Assert.Single(context.Result.Controllers);
var action = Assert.Single(controllerModel.Actions, a => a.ActionMethod.Name == nameof(ModelBinderController.PostAction));
Assert.Collection(
action.Parameters,
parameter =>
{
Assert.Equal("fromQuery", parameter.ParameterName);
Assert.Equal(BindingSource.Query, parameter.BindingInfo.BindingSource);
Assert.Same(action, parameter.Action);
var attribute = Assert.Single(parameter.Attributes);
Assert.IsType<FromQueryAttribute>(attribute);
},
parameter =>
{
Assert.Equal("formFileCollection", parameter.ParameterName);
// BindingSource for IFormFileCollection comes from ModelMetadata which we are not using here.
Assert.Null(parameter.BindingInfo);
Assert.Same(action, parameter.Action);
Assert.Empty(parameter.Attributes);
},
parameter =>
{
Assert.Equal("unbound", parameter.ParameterName);
Assert.Null(parameter.BindingInfo);
Assert.Same(action, parameter.Action);
});
}
[Fact]
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_ReadFromModelMetadata()
{
// Arrange
var options = new MvcOptions { AllowValidatingTopLevelNodes = true };
var detailsProvider = new BindingSourceMetadataProvider(typeof(Guid), BindingSource.Special);
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
var provider = new TestApplicationModelProvider(Options.Create(options), modelMetadataProvider);
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
var context = new ApplicationModelProviderContext(new[] { typeInfo });
// Act
provider.OnProvidersExecuting(context);
// Assert
var controllerModel = Assert.Single(context.Result.Controllers);
var action = Assert.Single(controllerModel.Actions, a => a.ActionName == nameof(ModelBinderController.PostAction1));
Assert.Collection(
action.Parameters,
parameter =>
{
Assert.Equal("guid", parameter.ParameterName);
Assert.Equal(BindingSource.Special, parameter.BindingInfo.BindingSource);
});
}
[Fact]
public void OnProvidersExecuting_UsesBindingSourceSpecifiedOnParameter()
{
// Arrange
var options = new MvcOptions();
var detailsProvider = new BindingSourceMetadataProvider(typeof(Guid), BindingSource.Special);
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
var provider = new TestApplicationModelProvider(Options.Create(options), modelMetadataProvider);
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
var context = new ApplicationModelProviderContext(new[] { typeInfo });
// Act
provider.OnProvidersExecuting(context);
// Assert
var controllerModel = Assert.Single(context.Result.Controllers);
var action = Assert.Single(controllerModel.Actions, a => a.ActionName == nameof(ModelBinderController.PostAction2));
Assert.Collection(
action.Parameters,
parameter =>
{
Assert.Equal("fromQuery", parameter.ParameterName);
Assert.Equal(BindingSource.Query, parameter.BindingInfo.BindingSource);
});
}
// This class has a filter attribute, but doesn't implement any filter interfaces,
// so ControllerFilter is not present.
[Fact]
@ -1363,6 +1508,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal
public IFormFile FormFile { get; set; }
public IActionResult PostAction([FromQuery] string fromQuery, IFormFileCollection formFileCollection, string unbound) => null;
public IActionResult PostAction1(Guid guid) => null;
public IActionResult PostAction2([FromQuery] Guid fromQuery) => null;
}
public class SomeFiltersController : IAsyncActionFilter, IResultFilter
@ -1404,13 +1553,14 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private class TestApplicationModelProvider : DefaultApplicationModelProvider
{
public TestApplicationModelProvider()
: this(Options.Create(new MvcOptions()))
: this(Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }), TestModelMetadataProvider.CreateDefaultProvider())
{
}
public TestApplicationModelProvider(
IOptions<MvcOptions> options)
: base(options)
IOptions<MvcOptions> options,
IModelMetadataProvider modelMetadataProvider)
: base(options, modelMetadataProvider)
{
}

View File

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
@ -23,10 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new [] { typeof(CorsController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(CorsController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -45,10 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(DisableCorsController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(DisableCorsController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -67,10 +62,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(CustomCorsFilterController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(CustomCorsFilterController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -88,10 +80,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(EnableCorsController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(EnableCorsController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -110,10 +99,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(DisableCorsActionController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(DisableCorsActionController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -132,10 +118,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(CustomCorsFilterOnActionController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(CustomCorsFilterOnActionController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -153,12 +136,10 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = GetProviderContext(typeof(RegularController));
var context = new ApplicationModelProviderContext(new[] { typeof(RegularController).GetTypeInfo() });
context.Result.Filters.Add(
new CorsAuthorizationFilter(Mock.Of<ICorsService>(), Mock.Of<ICorsPolicyProvider>(), Mock.Of<ILoggerFactory>()));
defaultProvider.OnProvidersExecuting(context);
// Act
corsProvider.OnProvidersExecuting(context);
@ -176,11 +157,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(RegularController).GetTypeInfo() });
var context = GetProviderContext(typeof(RegularController));
context.Result.Filters.Add(new DisableCorsAuthorizationFilter());
defaultProvider.OnProvidersExecuting(context);
// Act
corsProvider.OnProvidersExecuting(context);
@ -198,11 +176,8 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(RegularController).GetTypeInfo() });
var context = GetProviderContext(typeof(RegularController));
context.Result.Filters.Add(new CustomCorsFilterAttribute());
defaultProvider.OnProvidersExecuting(context);
// Act
corsProvider.OnProvidersExecuting(context);
@ -220,10 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
{
// Arrange
var corsProvider = new CorsApplicationModelProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var context = new ApplicationModelProviderContext(new[] { typeof(RegularController).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
var context = GetProviderContext(typeof(RegularController));
// Act
corsProvider.OnProvidersExecuting(context);
@ -236,6 +208,17 @@ namespace Microsoft.AspNetCore.Mvc.Cors.Internal
Assert.IsNotType<CorsHttpMethodActionConstraint>(constraint);
}
private static ApplicationModelProviderContext GetProviderContext(Type controllerType)
{
var context = new ApplicationModelProviderContext(new[] { controllerType.GetTypeInfo() });
var provider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
provider.OnProvidersExecuting(context);
return context;
}
private class EnableCorsController
{
[EnableCors("policy")]

View File

@ -88,7 +88,14 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
}
[Fact]
public async Task ActionsWithApiBehavior_InferFromBodyParameters()
public Task ActionsWithApiBehavior_InferFromBodyParameters()
=> ActionsWithApiBehaviorInferFromBodyParameters("ActionWithInferredFromBodyParameter");
[Fact]
public Task ActionsWithApiBehavior_InferFromBodyParameters_DoNotConsiderCancellationTokenSourceParameter()
=> ActionsWithApiBehaviorInferFromBodyParameters("ActionWithInferredFromBodyParameterAndCancellationToken");
private async Task ActionsWithApiBehaviorInferFromBodyParameters(string action)
{
// Arrange
var input = new Contact
@ -98,7 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
};
// Act
var response = await Client.PostAsJsonAsync("/contact/ActionWithInferredFromBodyParameter", input);
var response = await Client.PostAsJsonAsync($"/contact/{action}", input);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);

View File

@ -13,11 +13,12 @@ using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.IntegrationTests
@ -31,13 +32,9 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
public async Task AuthorizeFilter_CalledTwiceWithNonDefaultProvider()
{
// Arrange
var applicationModelProviderContext = new ApplicationModelProviderContext(
new[] { typeof(AuthorizeController).GetTypeInfo() });
var applicationModelProviderContext = GetProviderContext(typeof(AuthorizeController));
var policyProvider = new TestAuthorizationPolicyProvider();
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
defaultProvider.OnProvidersExecuting(applicationModelProviderContext);
var controller = Assert.Single(applicationModelProviderContext.Result.Controllers);
var action = Assert.Single(controller.Actions);
@ -64,6 +61,17 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
return httpContext;
}
private static ApplicationModelProviderContext GetProviderContext(Type controllerType)
{
var context = new ApplicationModelProviderContext(new[] { controllerType.GetTypeInfo() });
var provider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
provider.OnProvidersExecuting(context);
return context;
}
private static IServiceProvider GetServices()
{
var serviceCollection = new ServiceCollection();

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
using Xunit;
@ -160,7 +161,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private static PageApplicationModelProviderContext GetApplicationProviderContext(TypeInfo typeInfo)
{
var defaultProvider = new DefaultPageApplicationModelProvider();
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);
return context;

View File

@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_ThrowsIfPageDoesNotDeriveFromValidBaseType()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(InvalidPageWithWrongBaseClass).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -62,7 +63,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_ThrowsIfModelPropertyDoesNotExistOnPage()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithoutModelProperty).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -85,7 +86,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_ThrowsIfModelPropertyIsNotPublic()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithNonVisibleModel).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -110,7 +111,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_ThrowsIfModelPropertyIsStatic()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithStaticModel).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -135,7 +136,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversPropertiesFromPage_IfModelTypeDoesNotHaveAttribute()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithModelWithoutPageModelAttribute).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -189,7 +190,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversPropertiesFromPageModel_IfModelHasAttribute()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithModelWithPageModelAttribute).GetTypeInfo();
var modelType = typeof(ModelWithPageModelAttribute);
var descriptor = new PageActionDescriptor();
@ -233,7 +234,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversProperties_FromAllSubTypesThatDeclaresBindProperty()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(BindPropertyAttributeOnBaseModelPage).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -287,7 +288,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversHandlersFromPage()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithModelWithoutHandlers).GetTypeInfo();
var descriptor = new PageActionDescriptor();
var context = new PageApplicationModelProviderContext(descriptor, typeInfo);
@ -329,7 +330,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversPropertiesFromModel()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithModel).GetTypeInfo();
var modelType = typeof(TestPageModel);
var descriptor = new PageActionDescriptor();
@ -363,7 +364,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversBindingInfoFromHandler()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithBindPropertyModel).GetTypeInfo();
var modelType = typeof(ModelWithBindProperty);
var descriptor = new PageActionDescriptor();
@ -410,7 +411,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_DiscoversHandlersFromModel()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithModel).GetTypeInfo();
var modelType = typeof(TestPageModel);
var descriptor = new PageActionDescriptor();
@ -438,7 +439,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_EmptyPage()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(EmptyPage).GetTypeInfo();
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
@ -459,7 +460,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_EmptyPageModel()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(EmptyPageWithPageModel).GetTypeInfo();
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
@ -528,7 +529,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void CreateDescriptor_FindsHandlerMethod_OnModel()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithHandlerThatGetsIgnored).GetTypeInfo();
var modelType = typeof(ModelWithHandler);
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
@ -575,7 +576,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void OnProvidersExecuting_FindsHandlerMethodOnPage_WhenModelIsNotAnnotatedWithPageModelAttribute()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithHandler).GetTypeInfo();
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
@ -626,7 +627,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_DiscoversHandlersFromBaseType()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(InheritsMethods).GetTypeInfo();
var baseType = typeof(TestSetPageModel);
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -677,7 +678,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_IgnoresNonPublicMethods()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(ProtectedModel).GetTypeInfo();
var baseType = typeof(TestSetPageModel);
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -705,7 +706,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_IgnoreGenericTypeParameters()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(GenericClassModel).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -728,7 +729,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_IgnoresStaticMethods()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageModelWithStaticHandler).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageModelWithStaticHandler.OnGet), BindingFlags.Public | BindingFlags.Instance);
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -758,7 +759,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_IgnoresAbstractMethods()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageModelWithAbstractMethod).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageModelWithAbstractMethod.OnGet), BindingFlags.Public | BindingFlags.Instance);
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -786,7 +787,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerMethods_IgnoresMethodWithNonHandlerAttribute()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithNonHandlerMethod).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageWithNonHandlerMethod.OnGet), BindingFlags.Public | BindingFlags.Instance);
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -817,7 +818,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void CreateHandlerModel_ParsesMethod()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageModelWithHandlerNames).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -851,7 +852,42 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void CreateHandlerMethods_AddsParameterDescriptors()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(PageWithHandlerParameters).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageWithHandlerParameters.OnPost));
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
// Act
provider.PopulateHandlerMethods(pageModel);
// Assert
var handlerMethods = pageModel.HandlerMethods;
var handler = Assert.Single(handlerMethods);
Assert.Collection(
handler.Parameters,
p =>
{
Assert.NotNull(p.ParameterInfo);
Assert.Equal(typeof(string), p.ParameterInfo.ParameterType);
Assert.Equal("name", p.ParameterName);
},
p =>
{
Assert.NotNull(p.ParameterInfo);
Assert.Equal(typeof(int), p.ParameterInfo.ParameterType);
Assert.Equal("id", p.ParameterName);
Assert.Equal("personId", p.BindingInfo.BinderModelName);
});
}
[Fact]
public void CreateHandlerMethods_WithLegacyValidationBehavior_AddsParameterDescriptors()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false }));
var typeInfo = typeof(PageWithHandlerParameters).GetTypeInfo();
var expected = typeInfo.GetMethod(nameof(PageWithHandlerParameters.OnPost));
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -895,7 +931,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerProperties_UsesPropertyHelpers_ToFindProperties()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(HidesAProperty).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -928,7 +964,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateHandlerProperties_SupportsGet_OnProperty()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(ModelSupportsGetOnProperty).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, new object[0]);
@ -1039,7 +1075,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateFilters_AddsIFilterMetadataAttributesToModel()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(FilterModel).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
@ -1063,7 +1099,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateFilters_AddsPageHandlerPageFilter_IfPageImplementsIAsyncPageFilter()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(ModelImplementingAsyncPageFilter).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
@ -1093,7 +1129,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateFilters_AddsPageHandlerPageFilter_IfPageImplementsIPageFilter()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(ModelImplementingPageFilter).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
@ -1128,7 +1164,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
public void PopulateFilters_AddsPageHandlerPageFilter_ForModelDerivingFromTypeImplementingPageFilter()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider();
var provider = CreateProvider();
var typeInfo = typeof(DerivedFromPageModel).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
@ -1144,5 +1180,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
[ServiceFilter(typeof(IServiceProvider))]
private class DerivedFromPageModel : PageModel { }
private static DefaultPageApplicationModelProvider CreateProvider()
{
return new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }));
}
}
}

View File

@ -6,6 +6,7 @@ using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
@ -136,7 +137,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private static PageApplicationModelProviderContext GetApplicationProviderContext(TypeInfo typeInfo)
{
var defaultProvider = new DefaultPageApplicationModelProvider();
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new MvcOptions()));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);
return context;

View File

@ -183,6 +183,12 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal(BindingSource.FormFile, formCollectionParameter.BindingSource);
},
provider =>
{
var formFileParameter = Assert.IsType<BindingSourceMetadataProvider>(provider);
Assert.Equal(typeof(IFormFileCollection), formFileParameter.Type);
Assert.Equal(BindingSource.FormFile, formFileParameter.BindingSource);
},
provider =>
{
var excludeFilter = Assert.IsType<SuppressChildValidationMetadataProvider>(provider);
Assert.Equal(typeof(Type), excludeFilter.Type);
@ -208,6 +214,11 @@ namespace Microsoft.AspNetCore.Mvc
Assert.Equal(typeof(IFormCollection), excludeFilter.Type);
},
provider =>
{
var excludeFilter = Assert.IsType<SuppressChildValidationMetadataProvider>(provider);
Assert.Equal(typeof(IFormFileCollection), excludeFilter.Type);
},
provider =>
{
var excludeFilter = Assert.IsType<SuppressChildValidationMetadataProvider>(provider);
Assert.Equal(typeof(Stream), excludeFilter.Type);

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
// Creates a provider with all the defaults - includes data annotations
public static ModelMetadataProvider CreateDefaultProvider(IStringLocalizerFactory stringLocalizerFactory = null)
{
var detailsProviders = new IMetadataDetailsProvider[]
var detailsProviders = new List<IMetadataDetailsProvider>
{
new DefaultBindingMetadataProvider(),
new DefaultValidationMetadataProvider(),
@ -29,6 +29,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new DataMemberRequiredBindingMetadataProvider(),
};
MvcCoreMvcOptionsSetup.ConfigureAdditionalModelMetadataDetailsProvider(detailsProviders);
var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders);
return new DefaultModelMetadataProvider(compositeDetailsProvider, Options.Create(new MvcOptions()));
}
@ -45,6 +47,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
new DataMemberRequiredBindingMetadataProvider(),
};
MvcCoreMvcOptionsSetup.ConfigureAdditionalModelMetadataDetailsProvider(detailsProviders);
detailsProviders.AddRange(providers);
var compositeDetailsProvider = new DefaultCompositeMetadataDetailsProvider(detailsProviders);

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
using Xunit;
@ -20,7 +21,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var type = typeof(TestController_NoTempDataProperties);
var options = Options.Create(new MvcViewOptions());
var provider = new TempDataApplicationModelProvider(options);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
@ -41,7 +44,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var options = Options.Create(new MvcViewOptions());
var provider = new TempDataApplicationModelProvider(options);
var expected = $"The '{type.FullName}.Test' property with TempDataAttribute is invalid. A property using TempDataAttribute must have a public getter and setter.";
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
@ -58,7 +63,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var type = typeof(TestController_NullableNonPrimitiveTempDataProperty);
var options = Options.Create(new MvcViewOptions());
var provider = new TempDataApplicationModelProvider(options);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
@ -78,7 +85,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2));
var options = Options.Create(new MvcViewOptions());
var provider = new TempDataApplicationModelProvider(options);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { typeof(TestController_OneTempDataProperty).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);
@ -102,7 +111,9 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2));
var options = Options.Create(new MvcViewOptions { SuppressTempDataAttributePrefix = true });
var provider = new TempDataApplicationModelProvider(options);
var defaultProvider = new DefaultApplicationModelProvider(Options.Create(new MvcOptions()));
var defaultProvider = new DefaultApplicationModelProvider(
Options.Create(new MvcOptions()),
TestModelMetadataProvider.CreateDefaultProvider());
var context = new ApplicationModelProviderContext(new[] { typeof(TestController_OneTempDataProperty).GetTypeInfo() });
defaultProvider.OnProvidersExecuting(context);

View File

@ -379,22 +379,18 @@ namespace System.Web.Http
var setup = new WebApiCompatShimOptionsSetup();
setup.Configure(options);
var optionsAccessor = new Mock<IOptions<MvcOptions>>();
optionsAccessor
.SetupGet(o => o.Value)
.Returns(options);
var authorizationOptionsAccessor = new Mock<IOptions<AuthorizationOptions>>();
authorizationOptionsAccessor
.SetupGet(o => o.Value)
.Returns(new AuthorizationOptions());
var modelProvider = new DefaultApplicationModelProvider(optionsAccessor.Object);
var optionsAccessor = Options.Create(options);
var modelProvider = new DefaultApplicationModelProvider(optionsAccessor, TestModelMetadataProvider.CreateDefaultProvider());
var provider = new ControllerActionDescriptorProvider(
manager,
new[] { modelProvider },
optionsAccessor.Object);
optionsAccessor);
return provider;
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using BasicWebSite.Models;
using Microsoft.AspNetCore.Mvc;
@ -51,6 +52,10 @@ namespace BasicWebSite
[HttpPost("ActionWithInferredFromBodyParameter")]
public ActionResult<Contact> ActionWithInferredFromBodyParameter(Contact contact) => contact;
[HttpPost(nameof(ActionWithInferredFromBodyParameterAndCancellationToken))]
public ActionResult<Contact> ActionWithInferredFromBodyParameterAndCancellationToken(Contact contact, CancellationToken cts)
=> contact;
[HttpPost("ActionWithInferredRouteAndQueryParameters/{name}/{id}")]
public ActionResult<Contact> ActionWithInferredRouteAndQueryParameter(int id, string name, string email)
{
@ -68,4 +73,4 @@ namespace BasicWebSite
return contact;
}
}
}
}