Remove many `CompatibilitySwitch<T>` properties (#4628)
- #7156 2 of 3 - will leave the `IEnumerable<ICompatibilitySwitch>` implementations to avoid `breakingchanges.netcore.json` churn - will leave one `ConfigureCompatibilityOptions<MvcOptions>` subclass: `MvcOptionsConfigureCompatibilityOptions` - a few options remain as regular properties: - `ApiBehaviorOptions.SuppressMapClientErrors` (default `false`) - `MvcOptions.EnableEndpointRouting` (default `true`) - `MvcOptions.MaxValidationDepth` (default `32`) - `MvcJsonOptions.AllowInputFormatterExceptionMessages` (default `true`) nits: - move `IsEffectivePolicy(...)` check earlier in `AuthorizeFilter` - correct a typo or two
This commit is contained in:
parent
826f950530
commit
708dc5cb5a
|
|
@ -24,7 +24,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
public class DefaultApiDescriptionProvider : IApiDescriptionProvider
|
public class DefaultApiDescriptionProvider : IApiDescriptionProvider
|
||||||
{
|
{
|
||||||
private readonly MvcOptions _mvcOptions;
|
private readonly MvcOptions _mvcOptions;
|
||||||
private readonly IActionResultTypeMapper _mapper;
|
|
||||||
private readonly ApiResponseTypeProvider _responseTypeProvider;
|
private readonly ApiResponseTypeProvider _responseTypeProvider;
|
||||||
private readonly RouteOptions _routeOptions;
|
private readonly RouteOptions _routeOptions;
|
||||||
private readonly IInlineConstraintResolver _constraintResolver;
|
private readonly IInlineConstraintResolver _constraintResolver;
|
||||||
|
|
@ -53,7 +52,8 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> used for resolving inline
|
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> used for resolving inline
|
||||||
/// constraints.</param>
|
/// constraints.</param>
|
||||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||||
/// <param name="mapper"> The <see cref="IActionResultTypeMapper"/>.</param>
|
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
||||||
|
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
|
||||||
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
|
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
|
||||||
public DefaultApiDescriptionProvider(
|
public DefaultApiDescriptionProvider(
|
||||||
IOptions<MvcOptions> optionsAccessor,
|
IOptions<MvcOptions> optionsAccessor,
|
||||||
|
|
@ -64,7 +64,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
_mvcOptions = optionsAccessor.Value;
|
_mvcOptions = optionsAccessor.Value;
|
||||||
_constraintResolver = constraintResolver;
|
_constraintResolver = constraintResolver;
|
||||||
_modelMetadataProvider = modelMetadataProvider;
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
_mapper = mapper;
|
|
||||||
_responseTypeProvider = new ApiResponseTypeProvider(modelMetadataProvider, mapper, _mvcOptions);
|
_responseTypeProvider = new ApiResponseTypeProvider(modelMetadataProvider, mapper, _mvcOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,8 +74,9 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> used for resolving inline
|
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> used for resolving inline
|
||||||
/// constraints.</param>
|
/// constraints.</param>
|
||||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||||
/// <param name="mapper"> The <see cref="IActionResultTypeMapper"/>.</param>
|
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
||||||
/// <param name="routeOptions">The accessor for <see cref="RouteOptions"/>.</param>
|
/// <param name="routeOptions">The accessor for <see cref="RouteOptions"/>.</param>
|
||||||
|
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
|
||||||
public DefaultApiDescriptionProvider(
|
public DefaultApiDescriptionProvider(
|
||||||
IOptions<MvcOptions> optionsAccessor,
|
IOptions<MvcOptions> optionsAccessor,
|
||||||
IInlineConstraintResolver constraintResolver,
|
IInlineConstraintResolver constraintResolver,
|
||||||
|
|
@ -87,7 +87,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
_mvcOptions = optionsAccessor.Value;
|
_mvcOptions = optionsAccessor.Value;
|
||||||
_constraintResolver = constraintResolver;
|
_constraintResolver = constraintResolver;
|
||||||
_modelMetadataProvider = modelMetadataProvider;
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
_mapper = mapper;
|
|
||||||
_responseTypeProvider = new ApiResponseTypeProvider(modelMetadataProvider, mapper, _mvcOptions);
|
_responseTypeProvider = new ApiResponseTypeProvider(modelMetadataProvider, mapper, _mvcOptions);
|
||||||
_routeOptions = routeOptions.Value;
|
_routeOptions = routeOptions.Value;
|
||||||
}
|
}
|
||||||
|
|
@ -202,8 +201,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
var visitor = new PseudoModelBindingVisitor(context, actionParameter);
|
var visitor = new PseudoModelBindingVisitor(context, actionParameter);
|
||||||
|
|
||||||
ModelMetadata metadata;
|
ModelMetadata metadata;
|
||||||
if (_mvcOptions.AllowValidatingTopLevelNodes &&
|
if (actionParameter is ControllerParameterDescriptor controllerParameterDescriptor &&
|
||||||
actionParameter is ControllerParameterDescriptor controllerParameterDescriptor &&
|
|
||||||
_modelMetadataProvider is ModelMetadataProvider provider)
|
_modelMetadataProvider is ModelMetadataProvider provider)
|
||||||
{
|
{
|
||||||
// The default model metadata provider derives from ModelMetadataProvider
|
// The default model metadata provider derives from ModelMetadataProvider
|
||||||
|
|
|
||||||
|
|
@ -15,29 +15,9 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ApiBehaviorOptions : IEnumerable<ICompatibilitySwitch>
|
public class ApiBehaviorOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _suppressMapClientErrors;
|
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly CompatibilitySwitch<bool> _suppressUseValidationProblemDetailsForInvalidModelStateResponses;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowInferringBindingSourceForCollectionTypesAsFromQuery;
|
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
|
|
||||||
private Func<ActionContext, IActionResult> _invalidModelStateResponseFactory;
|
private Func<ActionContext, IActionResult> _invalidModelStateResponseFactory;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="ApiBehaviorOptions"/>.
|
|
||||||
/// </summary>
|
|
||||||
public ApiBehaviorOptions()
|
|
||||||
{
|
|
||||||
_suppressMapClientErrors = new CompatibilitySwitch<bool>(nameof(SuppressMapClientErrors));
|
|
||||||
_suppressUseValidationProblemDetailsForInvalidModelStateResponses = new CompatibilitySwitch<bool>(nameof(SuppressUseValidationProblemDetailsForInvalidModelStateResponses));
|
|
||||||
_allowInferringBindingSourceForCollectionTypesAsFromQuery = new CompatibilitySwitch<bool>(nameof(AllowInferringBindingSourceForCollectionTypesAsFromQuery));
|
|
||||||
_switches = new[]
|
|
||||||
{
|
|
||||||
_suppressMapClientErrors,
|
|
||||||
_suppressUseValidationProblemDetailsForInvalidModelStateResponses,
|
|
||||||
_allowInferringBindingSourceForCollectionTypesAsFromQuery
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delegate invoked on actions annotated with <see cref="ApiControllerAttribute"/> to convert invalid
|
/// Delegate invoked on actions annotated with <see cref="ApiControllerAttribute"/> to convert invalid
|
||||||
/// <see cref="ModelStateDictionary"/> into an <see cref="IActionResult"/>
|
/// <see cref="ModelStateDictionary"/> into an <see cref="IActionResult"/>
|
||||||
|
|
@ -92,47 +72,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The default value is <see langword="false"/>.
|
/// The default value is <see langword="false"/>.
|
||||||
/// </value>
|
/// </value>
|
||||||
public bool SuppressMapClientErrors
|
public bool SuppressMapClientErrors { get; set; }
|
||||||
{
|
|
||||||
// Note: When compatibility switches are removed in 3.0, this property should be retained as a regular boolean property.
|
|
||||||
get => _suppressMapClientErrors.Value;
|
|
||||||
set => _suppressMapClientErrors.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value that determines if controllers annotated with <see cref="ApiControllerAttribute"/> respond using
|
|
||||||
/// <see cref="ValidationProblemDetails"/> in <see cref="InvalidModelStateResponseFactory"/>.
|
|
||||||
/// <para>
|
|
||||||
/// When <see langword="true"/>, <see cref="SuppressModelStateInvalidFilter"/> returns errors in <see cref="ModelStateDictionary"/>
|
|
||||||
/// as a <see cref="ValidationProblemDetails"/>. Otherwise, <see cref="SuppressModelStateInvalidFilter"/> returns the errors
|
|
||||||
/// in the format determined by <see cref="SerializableError"/>.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// The default value is <see langword="false"/>.
|
|
||||||
/// </value>
|
|
||||||
public bool SuppressUseValidationProblemDetailsForInvalidModelStateResponses
|
|
||||||
{
|
|
||||||
get => _suppressUseValidationProblemDetailsForInvalidModelStateResponses.Value;
|
|
||||||
set => _suppressUseValidationProblemDetailsForInvalidModelStateResponses.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value that determines if <see cref="BindingInfo.BindingSource"/> for collection types
|
|
||||||
/// (<see cref="ModelMetadata.IsCollectionType"/>).
|
|
||||||
/// <para>
|
|
||||||
/// When <see langword="true" />, the binding source for collection types is inferred as <see cref="BindingSource.Query"/>.
|
|
||||||
/// Otherwise <see cref="BindingSource.Body"/> is inferred.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// The default value is <see langword="false"/>.
|
|
||||||
/// </value>
|
|
||||||
public bool AllowInferringBindingSourceForCollectionTypesAsFromQuery
|
|
||||||
{
|
|
||||||
get => _allowInferringBindingSourceForCollectionTypesAsFromQuery.Value;
|
|
||||||
set => _allowInferringBindingSourceForCollectionTypesAsFromQuery.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a map of HTTP status codes to <see cref="ClientErrorData"/>. Configured values
|
/// Gets a map of HTTP status codes to <see cref="ClientErrorData"/>. Configured values
|
||||||
|
|
@ -142,8 +82,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// Use of this feature can be disabled by resetting <see cref="SuppressMapClientErrors"/>.
|
/// Use of this feature can be disabled by resetting <see cref="SuppressMapClientErrors"/>.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } =
|
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } = new Dictionary<int, ClientErrorData>();
|
||||||
new Dictionary<int, ClientErrorData>();
|
|
||||||
|
|
||||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
|
||||||
if (!options.SuppressInferBindingSourcesForParameters)
|
if (!options.SuppressInferBindingSourcesForParameters)
|
||||||
{
|
{
|
||||||
var convention = new InferParameterBindingInfoConvention(modelMetadataProvider)
|
ActionModelConventions.Add(new InferParameterBindingInfoConvention(modelMetadataProvider));
|
||||||
{
|
|
||||||
AllowInferringBindingSourceForCollectionTypesAsFromQuery = options.AllowInferringBindingSourceForCollectionTypesAsFromQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
ActionModelConventions.Add(convention);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
var attributes = parameterInfo.GetCustomAttributes(inherit: true);
|
var attributes = parameterInfo.GetCustomAttributes(inherit: true);
|
||||||
|
|
||||||
BindingInfo bindingInfo;
|
BindingInfo bindingInfo;
|
||||||
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||||
{
|
{
|
||||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
||||||
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
/// An <see cref="IActionModelConvention"/> that infers <see cref="BindingInfo.BindingSource"/> for parameters.
|
/// An <see cref="IActionModelConvention"/> that infers <see cref="BindingInfo.BindingSource"/> for parameters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The goal of this covention is to make intuitive and easy to document <see cref="BindingSource"/> inferences. The rules are:
|
/// The goal of this convention is to make intuitive and easy to document <see cref="BindingSource"/> inferences. The rules are:
|
||||||
/// <list type="number">
|
/// <list type="number">
|
||||||
/// <item>A previously specified <see cref="BindingInfo.BindingSource" /> is never overwritten.</item>
|
/// <item>A previously specified <see cref="BindingInfo.BindingSource" /> is never overwritten.</item>
|
||||||
/// <item>A complex type parameter (<see cref="ModelMetadata.IsComplexType"/>) is assigned <see cref="BindingSource.Body"/>.</item>
|
/// <item>A complex type parameter (<see cref="ModelMetadata.IsComplexType"/>) is assigned <see cref="BindingSource.Body"/>.</item>
|
||||||
|
|
@ -31,8 +31,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
_modelMetadataProvider = modelMetadataProvider ?? throw new ArgumentNullException(nameof(modelMetadataProvider));
|
_modelMetadataProvider = modelMetadataProvider ?? throw new ArgumentNullException(nameof(modelMetadataProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool AllowInferringBindingSourceForCollectionTypesAsFromQuery { get; set; }
|
|
||||||
|
|
||||||
protected virtual bool ShouldApply(ActionModel action) => true;
|
protected virtual bool ShouldApply(ActionModel action) => true;
|
||||||
|
|
||||||
public void Apply(ActionModel action)
|
public void Apply(ActionModel action)
|
||||||
|
|
@ -118,13 +116,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
private bool IsComplexTypeParameter(ParameterModel parameter)
|
private bool IsComplexTypeParameter(ParameterModel parameter)
|
||||||
{
|
{
|
||||||
// No need for information from attributes on the parameter. Just use its type.
|
// No need for information from attributes on the parameter. Just use its type.
|
||||||
var metadata = _modelMetadataProvider
|
var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterInfo.ParameterType);
|
||||||
.GetMetadataForType(parameter.ParameterInfo.ParameterType);
|
|
||||||
|
|
||||||
if (AllowInferringBindingSourceForCollectionTypesAsFromQuery && metadata.IsCollectionType)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadata.IsComplexType;
|
return metadata.IsComplexType;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Core;
|
using Microsoft.AspNetCore.Mvc.Core;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Authorization
|
namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
|
|
@ -23,7 +22,6 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AuthorizeFilter : IAsyncAuthorizationFilter, IFilterFactory
|
public class AuthorizeFilter : IAsyncAuthorizationFilter, IFilterFactory
|
||||||
{
|
{
|
||||||
private MvcOptions _mvcOptions;
|
|
||||||
private AuthorizationPolicy _effectivePolicy;
|
private AuthorizationPolicy _effectivePolicy;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -136,38 +134,25 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
var effectivePolicy = await ComputePolicyAsync();
|
var effectivePolicy = await ComputePolicyAsync();
|
||||||
var canCache = PolicyProvider == null;
|
var canCache = PolicyProvider == null;
|
||||||
|
|
||||||
if (_mvcOptions == null)
|
// Combine all authorize filters into single effective policy that's only run on the closest filter
|
||||||
|
var builder = new AuthorizationPolicyBuilder(effectivePolicy);
|
||||||
|
for (var i = 0; i < context.Filters.Count; i++)
|
||||||
{
|
{
|
||||||
_mvcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value;
|
if (ReferenceEquals(this, context.Filters[i]))
|
||||||
}
|
|
||||||
|
|
||||||
if (_mvcOptions.AllowCombiningAuthorizeFilters)
|
|
||||||
{
|
|
||||||
if (!context.IsEffectivePolicy(this))
|
|
||||||
{
|
{
|
||||||
return null;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine all authorize filters into single effective policy that's only run on the closest filter
|
if (context.Filters[i] is AuthorizeFilter authorizeFilter)
|
||||||
var builder = new AuthorizationPolicyBuilder(effectivePolicy);
|
|
||||||
for (var i = 0; i < context.Filters.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(this, context.Filters[i]))
|
// Combine using the explicit policy, or the dynamic policy provider
|
||||||
{
|
builder.Combine(await authorizeFilter.ComputePolicyAsync());
|
||||||
continue;
|
canCache = canCache && authorizeFilter.PolicyProvider == null;
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Filters[i] is AuthorizeFilter authorizeFilter)
|
|
||||||
{
|
|
||||||
// Combine using the explicit policy, or the dynamic policy provider
|
|
||||||
builder.Combine(await authorizeFilter.ComputePolicyAsync());
|
|
||||||
canCache = canCache && authorizeFilter.PolicyProvider == null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
effectivePolicy = builder?.Build() ?? effectivePolicy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
effectivePolicy = builder?.Build() ?? effectivePolicy;
|
||||||
|
|
||||||
// We can cache the effective policy when there is no custom policy provider
|
// We can cache the effective policy when there is no custom policy provider
|
||||||
if (canCache)
|
if (canCache)
|
||||||
{
|
{
|
||||||
|
|
@ -185,6 +170,11 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
throw new ArgumentNullException(nameof(context));
|
throw new ArgumentNullException(nameof(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!context.IsEffectivePolicy(this))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var effectivePolicy = await GetEffectivePolicyAsync(context);
|
var effectivePolicy = await GetEffectivePolicyAsync(context);
|
||||||
if (effectivePolicy == null)
|
if (effectivePolicy == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// ASP.NET Core MVC 2.1 introduced compatibility switches for the following:
|
/// ASP.NET Core MVC 2.1 introduced compatibility switches for the following:
|
||||||
/// <list type="bullet">
|
/// <list type="bullet">
|
||||||
/// <item><description><see cref="MvcOptions.AllowBindingHeaderValuesToNonStringModelTypes"/></description></item>
|
|
||||||
/// <item><description><see cref="MvcOptions.InputFormatterExceptionPolicy"/></description></item>
|
|
||||||
/// <item><description><see cref="MvcOptions.InputFormatterExceptionPolicy"/></description></item>
|
/// <item><description><see cref="MvcOptions.InputFormatterExceptionPolicy"/></description></item>
|
||||||
/// <item><description><see cref="MvcOptions.SuppressBindingUndefinedValueToEnumType"/></description></item>
|
/// <item><description><see cref="MvcOptions.SuppressBindingUndefinedValueToEnumType"/></description></item>
|
||||||
/// <item><description><c>MvcJsonOptions.AllowInputFormatterExceptionMessages</c></description></item>
|
/// <item><description><c>MvcJsonOptions.AllowInputFormatterExceptionMessages</c></description></item>
|
||||||
|
|
@ -75,7 +73,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// ASP.NET Core MVC 2.2 introduced compatibility switches for the following:
|
/// ASP.NET Core MVC 2.2 introduced compatibility switches for the following:
|
||||||
/// <list type="bullet">
|
/// <list type="bullet">
|
||||||
/// <item><description><c>ApiBehaviorOptions.SuppressMapClientErrors</c></description></item>
|
/// <item><description><c>ApiBehaviorOptions.SuppressMapClientErrors</c></description></item>
|
||||||
/// <item><description><c>ApiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses</c></description></item>
|
|
||||||
/// <item><description><c>MvcDataAnnotationsLocalizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes</c></description></item>
|
/// <item><description><c>MvcDataAnnotationsLocalizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes</c></description></item>
|
||||||
/// <item><description><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
|
/// <item><description><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
|
||||||
/// <item><description><see cref="MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent"/></description></item>
|
/// <item><description><see cref="MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent"/></description></item>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Controllers
|
namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
|
|
@ -134,8 +133,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
var parameter = parameters[i];
|
var parameter = parameters[i];
|
||||||
|
|
||||||
ModelMetadata metadata;
|
ModelMetadata metadata;
|
||||||
if (mvcOptions.AllowValidatingTopLevelNodes &&
|
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
|
||||||
parameter is ControllerParameterDescriptor controllerParameterDescriptor)
|
parameter is ControllerParameterDescriptor controllerParameterDescriptor)
|
||||||
{
|
{
|
||||||
// The default model metadata provider derives from ModelMetadataProvider
|
// The default model metadata provider derives from ModelMetadataProvider
|
||||||
|
|
|
||||||
|
|
@ -2,37 +2,21 @@
|
||||||
// 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 Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Core;
|
using Microsoft.AspNetCore.Mvc.Core;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
internal class ApiBehaviorOptionsSetup :
|
internal class ApiBehaviorOptionsSetup :
|
||||||
ConfigureCompatibilityOptions<ApiBehaviorOptions>,
|
IConfigureOptions<ApiBehaviorOptions>,
|
||||||
IConfigureOptions<ApiBehaviorOptions>
|
IPostConfigureOptions<ApiBehaviorOptions>
|
||||||
{
|
{
|
||||||
internal static readonly Func<ActionContext, IActionResult> DefaultFactory = DefaultInvalidModelStateResponse;
|
internal static readonly Func<ActionContext, IActionResult> DefaultFactory = DefaultInvalidModelStateResponse;
|
||||||
internal static readonly Func<ActionContext, IActionResult> ProblemDetailsFactory = ProblemDetailsInvalidModelStateResponse;
|
internal static readonly Func<ActionContext, IActionResult> ProblemDetailsFactory =
|
||||||
|
ProblemDetailsInvalidModelStateResponse;
|
||||||
public ApiBehaviorOptionsSetup(
|
|
||||||
ILoggerFactory loggerFactory,
|
|
||||||
IOptions<MvcCompatibilityOptions> compatibilityOptions)
|
|
||||||
: base(loggerFactory, compatibilityOptions)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDictionary<string, object> DefaultValues
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new Dictionary<string, object>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(ApiBehaviorOptions options)
|
public void Configure(ApiBehaviorOptions options)
|
||||||
{
|
{
|
||||||
|
|
@ -45,11 +29,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
ConfigureClientErrorMapping(options);
|
ConfigureClientErrorMapping(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostConfigure(string name, ApiBehaviorOptions options)
|
public void PostConfigure(string name, ApiBehaviorOptions options)
|
||||||
{
|
{
|
||||||
// Let compatibility switches do their thing.
|
|
||||||
base.PostConfigure(name, options);
|
|
||||||
|
|
||||||
// We want to use problem details factory only if
|
// We want to use problem details factory only if
|
||||||
// (a) it has not been opted out of (SuppressMapClientErrors = true)
|
// (a) it has not been opted out of (SuppressMapClientErrors = true)
|
||||||
// (b) a different factory was configured
|
// (b) a different factory was configured
|
||||||
|
|
|
||||||
|
|
@ -49,20 +49,22 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
|
|
||||||
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor)
|
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor)
|
||||||
{
|
{
|
||||||
var controllerContext = new ControllerContext(context.ActionContext);
|
var controllerContext = new ControllerContext(context.ActionContext)
|
||||||
// PERF: These are rarely going to be changed, so let's go copy-on-write.
|
{
|
||||||
controllerContext.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories);
|
// PERF: These are rarely going to be changed, so let's go copy-on-write.
|
||||||
|
ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories)
|
||||||
|
};
|
||||||
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
|
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
|
||||||
|
|
||||||
var cacheResult = _controllerActionInvokerCache.GetCachedResult(controllerContext);
|
var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||||
|
|
||||||
var invoker = new ControllerActionInvoker(
|
var invoker = new ControllerActionInvoker(
|
||||||
_logger,
|
_logger,
|
||||||
_diagnosticListener,
|
_diagnosticListener,
|
||||||
_mapper,
|
_mapper,
|
||||||
controllerContext,
|
controllerContext,
|
||||||
cacheResult.cacheEntry,
|
cacheEntry,
|
||||||
cacheResult.filters);
|
filters);
|
||||||
|
|
||||||
context.Result = invoker;
|
context.Result = invoker;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
return new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
[nameof(MvcOptions.AllowCombiningAuthorizeFilters)] = true,
|
|
||||||
[nameof(MvcOptions.AllowBindingHeaderValuesToNonStringModelTypes)] = true,
|
|
||||||
[nameof(MvcOptions.AllowValidatingTopLevelNodes)] = true,
|
|
||||||
[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions,
|
[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions,
|
||||||
[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true,
|
[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true,
|
||||||
[nameof(MvcOptions.EnableEndpointRouting)] = true,
|
|
||||||
|
|
||||||
// Matches JsonSerializerSettingsProvider.DefaultMaxDepth
|
|
||||||
[nameof(MvcOptions.MaxValidationDepth)] = 32,
|
|
||||||
|
|
||||||
[nameof(MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent)] = true,
|
[nameof(MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent)] = true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// The <see cref="IModelBinder"/> for binding <typeparamref name="TElement"/>.
|
/// The <see cref="IModelBinder"/> for binding <typeparamref name="TElement"/>.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <remarks>
|
|
||||||
/// The binder will not add an error for an unbound top-level model even if
|
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public ArrayModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
|
public ArrayModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
|
||||||
: base(elementBinder, loggerFactory)
|
: base(elementBinder, loggerFactory)
|
||||||
{
|
{
|
||||||
|
|
@ -59,11 +55,16 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
||||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||||
/// </param>
|
/// </param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <paramref name="allowValidatingTopLevelNodes"/> parameter is currently ignored.
|
||||||
|
/// <see cref="CollectionModelBinder{TElement}.AllowValidatingTopLevelNodes"/> is always <see langword="true"/>
|
||||||
|
/// in <see cref="ArrayModelBinder{TElement}"/>.
|
||||||
|
/// </remarks>
|
||||||
public ArrayModelBinder(
|
public ArrayModelBinder(
|
||||||
IModelBinder elementBinder,
|
IModelBinder elementBinder,
|
||||||
ILoggerFactory loggerFactory,
|
ILoggerFactory loggerFactory,
|
||||||
bool allowValidatingTopLevelNodes)
|
bool allowValidatingTopLevelNodes)
|
||||||
: base(elementBinder, loggerFactory, allowValidatingTopLevelNodes)
|
: base(elementBinder, loggerFactory, allowValidatingTopLevelNodes: true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
|
|
@ -28,12 +27,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
var binderType = typeof(ArrayModelBinder<>).MakeGenericType(elementType);
|
var binderType = typeof(ArrayModelBinder<>).MakeGenericType(elementType);
|
||||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||||
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
|
||||||
return (IModelBinder)Activator.CreateInstance(
|
return (IModelBinder)Activator.CreateInstance(
|
||||||
binderType,
|
binderType,
|
||||||
elementBinder,
|
elementBinder,
|
||||||
loggerFactory,
|
loggerFactory,
|
||||||
mvcOptions.AllowValidatingTopLevelNodes);
|
true /* allowValidatingTopLevelNodes */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="elementBinder">The <see cref="IModelBinder"/> for binding elements.</param>
|
/// <param name="elementBinder">The <see cref="IModelBinder"/> for binding elements.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <remarks>
|
|
||||||
/// The binder will not add an error for an unbound top-level model even if
|
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public CollectionModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
|
public CollectionModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
|
||||||
: this(elementBinder, loggerFactory, allowValidatingTopLevelNodes: false)
|
: this(elementBinder, loggerFactory, allowValidatingTopLevelNodes: true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,16 +192,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bindingContext">The <see cref="ModelBindingContext"/>.</param>
|
/// <param name="bindingContext">The <see cref="ModelBindingContext"/>.</param>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
|
||||||
/// This method should be called only when <see cref="MvcOptions.AllowValidatingTopLevelNodes" /> is
|
|
||||||
/// <see langword="true" /> and a top-level model was not bound.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// For back-compatibility reasons, <see cref="ModelBindingContext.Result" /> must have
|
/// For back-compatibility reasons, <see cref="ModelBindingContext.Result" /> must have
|
||||||
/// <see cref="ModelBindingResult.IsModelSet" /> equal to <see langword="true" /> when a
|
/// <see cref="ModelBindingResult.IsModelSet" /> equal to <see langword="true" /> when a
|
||||||
/// top-level model is not bound. Therefore, ParameterBinder can not detect a
|
/// top-level model is not bound. Therefore, ParameterBinder can not detect a
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired" /> failure for collections. Add the error here.
|
/// <see cref="ModelMetadata.IsBindingRequired" /> failure for collections. Add the error here.
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected void AddErrorIfBindingRequired(ModelBindingContext bindingContext)
|
protected void AddErrorIfBindingRequired(ModelBindingContext bindingContext)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
binderType,
|
binderType,
|
||||||
elementBinder,
|
elementBinder,
|
||||||
loggerFactory,
|
loggerFactory,
|
||||||
mvcOptions.AllowValidatingTopLevelNodes);
|
true /* allowValidatingTopLevelNodes */);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
|
// If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
binderType,
|
binderType,
|
||||||
elementBinder,
|
elementBinder,
|
||||||
loggerFactory,
|
loggerFactory,
|
||||||
mvcOptions.AllowValidatingTopLevelNodes);
|
true /* allowValidatingTopLevelNodes */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,14 +44,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// The <see cref="IDictionary{TKey, TValue}"/> of binders to use for binding properties.
|
/// The <see cref="IDictionary{TKey, TValue}"/> of binders to use for binding properties.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <remarks>
|
|
||||||
/// The binder will not add an error for an unbound top-level model even if
|
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public ComplexTypeModelBinder(
|
public ComplexTypeModelBinder(
|
||||||
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory)
|
||||||
: this(propertyBinders, loggerFactory, allowValidatingTopLevelNodes: false)
|
: this(propertyBinders, loggerFactory, allowValidatingTopLevelNodes: true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +63,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
||||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||||
/// </param>
|
/// </param>
|
||||||
|
/// <remarks>The <paramref name="allowValidatingTopLevelNodes"/> parameter is currently ignored.</remarks>
|
||||||
public ComplexTypeModelBinder(
|
public ComplexTypeModelBinder(
|
||||||
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
||||||
ILoggerFactory loggerFactory,
|
ILoggerFactory loggerFactory,
|
||||||
|
|
@ -84,13 +81,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
_propertyBinders = propertyBinders;
|
_propertyBinders = propertyBinders;
|
||||||
_logger = loggerFactory.CreateLogger<ComplexTypeModelBinder>();
|
_logger = loggerFactory.CreateLogger<ComplexTypeModelBinder>();
|
||||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing.
|
|
||||||
internal bool AllowValidatingTopLevelNodes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task BindModelAsync(ModelBindingContext bindingContext)
|
public Task BindModelAsync(ModelBindingContext bindingContext)
|
||||||
{
|
{
|
||||||
if (bindingContext == null)
|
if (bindingContext == null)
|
||||||
|
|
@ -172,8 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
// 1. The top-level model has no public settable properties.
|
// 1. The top-level model has no public settable properties.
|
||||||
// 2. All properties in a [BindRequired] model have [BindNever] or are otherwise excluded from binding.
|
// 2. All properties in a [BindRequired] model have [BindNever] or are otherwise excluded from binding.
|
||||||
// 3. No data exists for any property.
|
// 3. No data exists for any property.
|
||||||
if (AllowValidatingTopLevelNodes &&
|
if (!attemptedPropertyBinding &&
|
||||||
!attemptedPropertyBinding &&
|
|
||||||
bindingContext.IsTopLevelObject &&
|
bindingContext.IsTopLevelObject &&
|
||||||
modelMetadata.IsBindingRequired)
|
modelMetadata.IsBindingRequired)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
|
|
@ -32,11 +31,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||||
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
|
||||||
return new ComplexTypeModelBinder(
|
return new ComplexTypeModelBinder(
|
||||||
propertyBinders,
|
propertyBinders,
|
||||||
loggerFactory,
|
loggerFactory,
|
||||||
mvcOptions.AllowValidatingTopLevelNodes);
|
allowValidatingTopLevelNodes: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
|
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
|
||||||
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
|
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <remarks>
|
|
||||||
/// The binder will not add an error for an unbound top-level model even if
|
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public DictionaryModelBinder(IModelBinder keyBinder, IModelBinder valueBinder, ILoggerFactory loggerFactory)
|
public DictionaryModelBinder(IModelBinder keyBinder, IModelBinder valueBinder, ILoggerFactory loggerFactory)
|
||||||
: base(new KeyValuePairModelBinder<TKey, TValue>(keyBinder, valueBinder, loggerFactory), loggerFactory)
|
: base(new KeyValuePairModelBinder<TKey, TValue>(keyBinder, valueBinder, loggerFactory), loggerFactory)
|
||||||
{
|
{
|
||||||
|
|
@ -67,6 +63,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
/// <see cref="ModelMetadata.IsBindingRequired"/> is <see langword="true"/> for a top-level model, the binder
|
||||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||||
/// </param>
|
/// </param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <paramref name="allowValidatingTopLevelNodes"/> parameter is currently ignored.
|
||||||
|
/// <see cref="CollectionModelBinder{TElement}.AllowValidatingTopLevelNodes"/> is always
|
||||||
|
/// <see langword="false"/> in <see cref="DictionaryModelBinder{TKey, TValue}"/>. This class ignores that
|
||||||
|
/// property and unconditionally checks for unbound top-level models with
|
||||||
|
/// <see cref="ModelMetadata.IsBindingRequired"/>.
|
||||||
|
/// </remarks>
|
||||||
public DictionaryModelBinder(
|
public DictionaryModelBinder(
|
||||||
IModelBinder keyBinder,
|
IModelBinder keyBinder,
|
||||||
IModelBinder valueBinder,
|
IModelBinder valueBinder,
|
||||||
|
|
@ -84,12 +87,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
_valueBinder = valueBinder;
|
_valueBinder = valueBinder;
|
||||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing.
|
|
||||||
internal new bool AllowValidatingTopLevelNodes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task BindModelAsync(ModelBindingContext bindingContext)
|
public override async Task BindModelAsync(ModelBindingContext bindingContext)
|
||||||
{
|
{
|
||||||
|
|
@ -121,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
// No IEnumerableValueProvider available for the fallback approach. For example the user may have
|
// No IEnumerableValueProvider available for the fallback approach. For example the user may have
|
||||||
// replaced the ValueProvider with something other than a CompositeValueProvider.
|
// replaced the ValueProvider with something other than a CompositeValueProvider.
|
||||||
if (AllowValidatingTopLevelNodes && bindingContext.IsTopLevelObject)
|
if (bindingContext.IsTopLevelObject)
|
||||||
{
|
{
|
||||||
AddErrorIfBindingRequired(bindingContext);
|
AddErrorIfBindingRequired(bindingContext);
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +134,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
if (keys.Count == 0)
|
if (keys.Count == 0)
|
||||||
{
|
{
|
||||||
// No entries with the expected keys.
|
// No entries with the expected keys.
|
||||||
if (AllowValidatingTopLevelNodes && bindingContext.IsTopLevelObject)
|
if (bindingContext.IsTopLevelObject)
|
||||||
{
|
{
|
||||||
AddErrorIfBindingRequired(bindingContext);
|
AddErrorIfBindingRequired(bindingContext);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
keyBinder,
|
keyBinder,
|
||||||
valueBinder,
|
valueBinder,
|
||||||
loggerFactory,
|
loggerFactory,
|
||||||
mvcOptions.AllowValidatingTopLevelNodes);
|
true /* allowValidatingTopLevelNodes */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
|
|
@ -32,23 +31,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||||
var logger = loggerFactory.CreateLogger<HeaderModelBinderProvider>();
|
var logger = loggerFactory.CreateLogger<HeaderModelBinderProvider>();
|
||||||
|
|
||||||
var options = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
|
||||||
if (!options.AllowBindingHeaderValuesToNonStringModelTypes)
|
|
||||||
{
|
|
||||||
if (modelMetadata.ModelType == typeof(string) ||
|
|
||||||
modelMetadata.ElementType == typeof(string))
|
|
||||||
{
|
|
||||||
return new HeaderModelBinder(loggerFactory);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.CannotCreateHeaderModelBinderCompatVersion_2_0(modelMetadata.ModelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!IsSimpleType(modelMetadata))
|
if (!IsSimpleType(modelMetadata))
|
||||||
{
|
{
|
||||||
logger.CannotCreateHeaderModelBinder(modelMetadata.ModelType);
|
logger.CannotCreateHeaderModelBinder(modelMetadata.ModelType);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||||
private readonly IModelBinderFactory _modelBinderFactory;
|
private readonly IModelBinderFactory _modelBinderFactory;
|
||||||
private readonly MvcOptions _mvcOptions;
|
|
||||||
private readonly IObjectModelValidator _objectModelValidator;
|
private readonly IObjectModelValidator _objectModelValidator;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -55,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
|
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
|
||||||
/// <param name="mvcOptions">The <see cref="MvcOptions"/> accessor.</param>
|
/// <param name="mvcOptions">The <see cref="MvcOptions"/> accessor.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
|
/// <remarks>The <paramref name="mvcOptions"/> parameter is currently unused.</remarks>
|
||||||
public ParameterBinder(
|
public ParameterBinder(
|
||||||
IModelMetadataProvider modelMetadataProvider,
|
IModelMetadataProvider modelMetadataProvider,
|
||||||
IModelBinderFactory modelBinderFactory,
|
IModelBinderFactory modelBinderFactory,
|
||||||
|
|
@ -90,7 +90,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
_modelMetadataProvider = modelMetadataProvider;
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
_modelBinderFactory = modelBinderFactory;
|
_modelBinderFactory = modelBinderFactory;
|
||||||
_objectModelValidator = validator;
|
_objectModelValidator = validator;
|
||||||
_mvcOptions = mvcOptions.Value;
|
|
||||||
Logger = loggerFactory.CreateLogger(GetType());
|
Logger = loggerFactory.CreateLogger(GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,8 +259,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
|
|
||||||
var modelBindingResult = modelBindingContext.Result;
|
var modelBindingResult = modelBindingContext.Result;
|
||||||
|
|
||||||
if (_mvcOptions.AllowValidatingTopLevelNodes &&
|
if (_objectModelValidator is ObjectModelValidator baseObjectValidator)
|
||||||
_objectModelValidator is ObjectModelValidator baseObjectValidator)
|
|
||||||
{
|
{
|
||||||
Logger.AttemptingToValidateParameterOrProperty(parameter, metadata);
|
Logger.AttemptingToValidateParameterOrProperty(parameter, metadata);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
validatorProvider,
|
validatorProvider,
|
||||||
validatorCache,
|
validatorCache,
|
||||||
metadataProvider,
|
metadataProvider,
|
||||||
validationState);
|
validationState)
|
||||||
|
{
|
||||||
visitor.MaxValidationDepth = _mvcOptions.MaxValidationDepth;
|
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
|
||||||
visitor.AllowShortCircuitingValidationWhenNoValidatorsArePresent = _mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent;
|
AllowShortCircuitingValidationWhenNoValidatorsArePresent =
|
||||||
|
_mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent,
|
||||||
|
};
|
||||||
|
|
||||||
return visitor;
|
return visitor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
|
|
||||||
|
|
@ -22,18 +19,14 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
|
||||||
|
|
||||||
// See CompatibilitySwitch.cs for guide on how to implement these.
|
// See CompatibilitySwitch.cs for guide on how to implement these.
|
||||||
private readonly CompatibilitySwitch<bool> _allowBindingHeaderValuesToNonStringModelTypes;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowCombiningAuthorizeFilters;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowValidatingTopLevelNodes;
|
|
||||||
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
|
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
|
||||||
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
||||||
private readonly CompatibilitySwitch<bool> _enableEndpointRouting;
|
|
||||||
private readonly NullableCompatibilitySwitch<int> _maxValidationDepth;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowShortCircuitingValidationWhenNoValidatorsArePresent;
|
private readonly CompatibilitySwitch<bool> _allowShortCircuitingValidationWhenNoValidatorsArePresent;
|
||||||
|
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
private readonly ICompatibilitySwitch[] _switches;
|
||||||
|
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||||
|
private int? _maxValidationDepth = 32;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="MvcOptions"/>.
|
/// Creates a new instance of <see cref="MvcOptions"/>.
|
||||||
|
|
@ -52,24 +45,14 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||||
ValueProviderFactories = new List<IValueProviderFactory>();
|
ValueProviderFactories = new List<IValueProviderFactory>();
|
||||||
|
|
||||||
_allowCombiningAuthorizeFilters = new CompatibilitySwitch<bool>(nameof(AllowCombiningAuthorizeFilters));
|
|
||||||
_allowBindingHeaderValuesToNonStringModelTypes = new CompatibilitySwitch<bool>(nameof(AllowBindingHeaderValuesToNonStringModelTypes));
|
|
||||||
_allowValidatingTopLevelNodes = new CompatibilitySwitch<bool>(nameof(AllowValidatingTopLevelNodes));
|
|
||||||
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
|
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
|
||||||
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
||||||
_enableEndpointRouting = new CompatibilitySwitch<bool>(nameof(EnableEndpointRouting));
|
|
||||||
_maxValidationDepth = new NullableCompatibilitySwitch<int>(nameof(MaxValidationDepth));
|
|
||||||
_allowShortCircuitingValidationWhenNoValidatorsArePresent = new CompatibilitySwitch<bool>(nameof(AllowShortCircuitingValidationWhenNoValidatorsArePresent));
|
_allowShortCircuitingValidationWhenNoValidatorsArePresent = new CompatibilitySwitch<bool>(nameof(AllowShortCircuitingValidationWhenNoValidatorsArePresent));
|
||||||
|
|
||||||
_switches = new ICompatibilitySwitch[]
|
_switches = new ICompatibilitySwitch[]
|
||||||
{
|
{
|
||||||
_allowCombiningAuthorizeFilters,
|
|
||||||
_allowBindingHeaderValuesToNonStringModelTypes,
|
|
||||||
_allowValidatingTopLevelNodes,
|
|
||||||
_inputFormatterExceptionPolicy,
|
_inputFormatterExceptionPolicy,
|
||||||
_suppressBindingUndefinedValueToEnumType,
|
_suppressBindingUndefinedValueToEnumType,
|
||||||
_enableEndpointRouting,
|
|
||||||
_maxValidationDepth,
|
|
||||||
_allowShortCircuitingValidationWhenNoValidatorsArePresent,
|
_allowShortCircuitingValidationWhenNoValidatorsArePresent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -82,11 +65,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The default value is <see langword="true"/>.
|
/// The default value is <see langword="true"/>.
|
||||||
/// </value>
|
/// </value>
|
||||||
public bool EnableEndpointRouting
|
public bool EnableEndpointRouting { get; set; } = true;
|
||||||
{
|
|
||||||
get => _enableEndpointRouting.Value;
|
|
||||||
set => _enableEndpointRouting.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the flag which decides whether body model binding (for example, on an
|
/// Gets or sets the flag which decides whether body model binding (for example, on an
|
||||||
|
|
@ -100,58 +79,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </example>
|
/// </example>
|
||||||
public bool AllowEmptyInputInBodyModelBinding { get; set; }
|
public bool AllowEmptyInputInBodyModelBinding { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value that determines if policies on instances of <see cref="AuthorizeFilter" />
|
|
||||||
/// will be combined into a single effective policy.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// The default value is <see langword="true"/>.
|
|
||||||
/// </value>
|
|
||||||
/// <remarks>
|
|
||||||
/// Authorization policies are designed such that multiple authorization policies applied to an endpoint
|
|
||||||
/// should be combined and executed a single policy. The <see cref="AuthorizeFilter"/> (commonly applied
|
|
||||||
/// by <see cref="AuthorizeAttribute"/>) can be applied globally, to controllers, and to actions - which
|
|
||||||
/// specifies multiple authorization policies for an action. In all ASP.NET Core releases prior to 2.1
|
|
||||||
/// these multiple policies would not combine as intended. This compatibility switch configures whether the
|
|
||||||
/// old (unintended) behavior or the new combining behavior will be used when multiple authorization policies
|
|
||||||
/// are applied.
|
|
||||||
/// </remarks>
|
|
||||||
public bool AllowCombiningAuthorizeFilters
|
|
||||||
{
|
|
||||||
get => _allowCombiningAuthorizeFilters.Value;
|
|
||||||
set => _allowCombiningAuthorizeFilters.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value that determines if <see cref="HeaderModelBinder"/> should bind to types other than
|
|
||||||
/// <see cref="string"/> or a collection of <see cref="string"/>. If set to <c>true</c>,
|
|
||||||
/// <see cref="HeaderModelBinder"/> would bind to simple types (like <see cref="string"/>, <see cref="int"/>,
|
|
||||||
/// <see cref="Enum"/>, <see cref="bool"/> etc.) or a collection of simple types.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// The default value is <see langword="true"/>.
|
|
||||||
/// </value>
|
|
||||||
public bool AllowBindingHeaderValuesToNonStringModelTypes
|
|
||||||
{
|
|
||||||
get => _allowBindingHeaderValuesToNonStringModelTypes.Value;
|
|
||||||
set => _allowBindingHeaderValuesToNonStringModelTypes.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value that determines if model bound action parameters, controller properties, page handler
|
|
||||||
/// parameters, or page model properties are validated (in addition to validating their elements or
|
|
||||||
/// properties). If set to <see langword="true"/>, <see cref="BindRequiredAttribute"/> and
|
|
||||||
/// <c>ValidationAttribute</c>s on these top-level nodes are checked. Otherwise, such attributes are ignored.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// The default value is <see langword="true"/>.
|
|
||||||
/// </value>
|
|
||||||
public bool AllowValidatingTopLevelNodes
|
|
||||||
{
|
|
||||||
get => _allowValidatingTopLevelNodes.Value;
|
|
||||||
set => _allowValidatingTopLevelNodes.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a Dictionary of CacheProfile Names, <see cref="CacheProfile"/> which are pre-defined settings for
|
/// Gets a Dictionary of CacheProfile Names, <see cref="CacheProfile"/> which are pre-defined settings for
|
||||||
/// response caching.
|
/// response caching.
|
||||||
|
|
@ -311,7 +238,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </value>
|
/// </value>
|
||||||
public int? MaxValidationDepth
|
public int? MaxValidationDepth
|
||||||
{
|
{
|
||||||
get => _maxValidationDepth.Value;
|
get => _maxValidationDepth;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value != null && value <= 0)
|
if (value != null && value <= 0)
|
||||||
|
|
@ -319,7 +246,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
throw new ArgumentOutOfRangeException(nameof(value));
|
throw new ArgumentOutOfRangeException(nameof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_maxValidationDepth.Value = value;
|
_maxValidationDepth = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,5 +72,35 @@
|
||||||
"TypeId": "public abstract class Microsoft.AspNetCore.Mvc.ModelBinding.ObjectModelValidator : Microsoft.AspNetCore.Mvc.ModelBinding.Validation.IObjectModelValidator",
|
"TypeId": "public abstract class Microsoft.AspNetCore.Mvc.ModelBinding.ObjectModelValidator : Microsoft.AspNetCore.Mvc.ModelBinding.Validation.IObjectModelValidator",
|
||||||
"MemberId": "public abstract Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor GetValidationVisitor(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.IModelValidatorProvider validatorProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidatorCache validatorCache, Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider metadataProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateDictionary validationState)",
|
"MemberId": "public abstract Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationVisitor GetValidationVisitor(Microsoft.AspNetCore.Mvc.ActionContext actionContext, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.IModelValidatorProvider validatorProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidatorCache validatorCache, Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider metadataProvider, Microsoft.AspNetCore.Mvc.ModelBinding.Validation.ValidationStateDictionary validationState)",
|
||||||
"Kind": "Addition"
|
"Kind": "Addition"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Boolean get_AllowBindingHeaderValuesToNonStringModelTypes()",
|
||||||
|
"Kind": "Removal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Boolean get_AllowCombiningAuthorizeFilters()",
|
||||||
|
"Kind": "Removal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Boolean get_AllowValidatingTopLevelNodes()",
|
||||||
|
"Kind": "Removal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Void set_AllowBindingHeaderValuesToNonStringModelTypes(System.Boolean value)",
|
||||||
|
"Kind": "Removal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Void set_AllowCombiningAuthorizeFilters(System.Boolean value)",
|
||||||
|
"Kind": "Removal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
||||||
|
"MemberId": "public System.Void set_AllowValidatingTopLevelNodes(System.Boolean value)",
|
||||||
|
"Kind": "Removal"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -75,8 +75,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcJsonOptions>, MvcJsonOptionsConfigureCompatibilityOptions>());
|
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IApiDescriptionProvider, JsonPatchOperationsArrayProvider>());
|
ServiceDescriptor.Transient<IApiDescriptionProvider, JsonPatchOperationsArrayProvider>());
|
||||||
services.TryAddSingleton<JsonResultExecutor>();
|
services.TryAddSingleton<JsonResultExecutor>();
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
|
||||||
{
|
|
||||||
internal class MvcJsonOptionsConfigureCompatibilityOptions : ConfigureCompatibilityOptions<MvcJsonOptions>
|
|
||||||
{
|
|
||||||
public MvcJsonOptionsConfigureCompatibilityOptions(
|
|
||||||
ILoggerFactory loggerFactory,
|
|
||||||
IOptions<MvcCompatibilityOptions> compatibilityOptions)
|
|
||||||
: base(loggerFactory, compatibilityOptions)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IReadOnlyDictionary<string, object> DefaultValues
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
[nameof(MvcJsonOptions.AllowInputFormatterExceptionMessages)] = true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
|
|
@ -15,21 +16,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _allowInputFormatterExceptionMessages;
|
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="MvcJsonOptions"/>.
|
|
||||||
/// </summary>
|
|
||||||
public MvcJsonOptions()
|
|
||||||
{
|
|
||||||
_allowInputFormatterExceptionMessages = new CompatibilitySwitch<bool>(nameof(AllowInputFormatterExceptionMessages));
|
|
||||||
|
|
||||||
_switches = new ICompatibilitySwitch[]
|
|
||||||
{
|
|
||||||
_allowInputFormatterExceptionMessages,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a flag to determine whether error messages from JSON deserialization by the
|
/// Gets or sets a flag to determine whether error messages from JSON deserialization by the
|
||||||
|
|
@ -44,11 +31,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// or using <see cref="BadRequestObjectResult"/>. In effect, this setting controls whether clients can receive
|
/// or using <see cref="BadRequestObjectResult"/>. In effect, this setting controls whether clients can receive
|
||||||
/// detailed error messages about submitted JSON data.
|
/// detailed error messages about submitted JSON data.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool AllowInputFormatterExceptionMessages
|
public bool AllowInputFormatterExceptionMessages { get; set; } = true;
|
||||||
{
|
|
||||||
get => _allowInputFormatterExceptionMessages.Value;
|
|
||||||
set => _allowInputFormatterExceptionMessages.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="JsonSerializerSettings"/> that are used by this application.
|
/// Gets the <see cref="JsonSerializerSettings"/> that are used by this application.
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
/// This type will never be used for deserialization, but we are required to implement the add
|
/// This type will never be used for deserialization, but we are required to implement the add
|
||||||
/// method so that the type can be serialized. This will never be called.
|
/// method so that the type can be serialized. This will never be called.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item to add. Unused.</param>
|
/// <param name="item">The item to add.</param>
|
||||||
|
/// <exception cref="NotImplementedException">Thrown unconditionally.</exception>
|
||||||
public void Add(object item)
|
public void Add(object item)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
private readonly PageHandlerPageFilter _pageHandlerPageFilter = new PageHandlerPageFilter();
|
private readonly PageHandlerPageFilter _pageHandlerPageFilter = new PageHandlerPageFilter();
|
||||||
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
|
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
|
||||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||||
private readonly MvcOptions _mvcOptions;
|
|
||||||
private readonly RazorPagesOptions _razorPagesOptions;
|
private readonly RazorPagesOptions _razorPagesOptions;
|
||||||
private readonly Func<ActionContext, bool> _supportsAllRequests;
|
private readonly Func<ActionContext, bool> _supportsAllRequests;
|
||||||
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
|
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
|
||||||
|
|
@ -29,11 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
|
||||||
public DefaultPageApplicationModelProvider(
|
public DefaultPageApplicationModelProvider(
|
||||||
IModelMetadataProvider modelMetadataProvider,
|
IModelMetadataProvider modelMetadataProvider,
|
||||||
IOptions<MvcOptions> options,
|
|
||||||
IOptions<RazorPagesOptions> razorPagesOptions)
|
IOptions<RazorPagesOptions> razorPagesOptions)
|
||||||
{
|
{
|
||||||
_modelMetadataProvider = modelMetadataProvider;
|
_modelMetadataProvider = modelMetadataProvider;
|
||||||
_mvcOptions = options.Value;
|
|
||||||
_razorPagesOptions = razorPagesOptions.Value;
|
_razorPagesOptions = razorPagesOptions.Value;
|
||||||
|
|
||||||
_supportsAllRequests = _ => true;
|
_supportsAllRequests = _ => true;
|
||||||
|
|
@ -248,7 +245,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
var attributes = parameter.GetCustomAttributes(inherit: true);
|
var attributes = parameter.GetCustomAttributes(inherit: true);
|
||||||
|
|
||||||
BindingInfo bindingInfo;
|
BindingInfo bindingInfo;
|
||||||
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||||
{
|
{
|
||||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
|
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
|
||||||
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
var parameter = handler.Parameters[i];
|
var parameter = handler.Parameters[i];
|
||||||
ModelMetadata metadata;
|
ModelMetadata metadata;
|
||||||
if (mvcOptions.AllowValidatingTopLevelNodes &&
|
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
|
||||||
{
|
{
|
||||||
// The default model metadata provider derives from ModelMetadataProvider
|
// The default model metadata provider derives from ModelMetadataProvider
|
||||||
// and can therefore supply information about attributes applied to parameters.
|
// and can therefore supply information about attributes applied to parameters.
|
||||||
|
|
|
||||||
|
|
@ -1180,25 +1180,6 @@ namespace Microsoft.AspNetCore.Mvc.Description
|
||||||
Assert.True(parameter.ModelMetadata.IsBindingRequired);
|
Assert.True(parameter.ModelMetadata.IsBindingRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void GetApiDescription_ParameterDescription_IsRequiredNotSet_IfNotValidatingTopLevelNodes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var action = CreateActionDescriptor(nameof(RequiredParameter));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var descriptions = GetApiDescriptions(action, allowValidatingTopLevelNodes: false);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var description = Assert.Single(descriptions);
|
|
||||||
var parameter = Assert.Single(description.ParameterDescriptions);
|
|
||||||
Assert.Equal("name", parameter.Name);
|
|
||||||
Assert.Same(BindingSource.ModelBinding, parameter.Source);
|
|
||||||
Assert.Equal(typeof(string), parameter.Type);
|
|
||||||
Assert.False(parameter.ModelMetadata.IsRequired);
|
|
||||||
Assert.False(parameter.ModelMetadata.IsBindingRequired);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetApiDescription_ParameterDescription_SourceFromRouteData()
|
public void GetApiDescription_ParameterDescription_SourceFromRouteData()
|
||||||
{
|
{
|
||||||
|
|
@ -1816,15 +1797,11 @@ namespace Microsoft.AspNetCore.Mvc.Description
|
||||||
ActionDescriptor action,
|
ActionDescriptor action,
|
||||||
List<MockInputFormatter> inputFormatters = null,
|
List<MockInputFormatter> inputFormatters = null,
|
||||||
List<MockOutputFormatter> outputFormatters = null,
|
List<MockOutputFormatter> outputFormatters = null,
|
||||||
bool allowValidatingTopLevelNodes = true,
|
|
||||||
RouteOptions routeOptions = null)
|
RouteOptions routeOptions = null)
|
||||||
{
|
{
|
||||||
var context = new ApiDescriptionProviderContext(new ActionDescriptor[] { action });
|
var context = new ApiDescriptionProviderContext(new ActionDescriptor[] { action });
|
||||||
|
|
||||||
var options = new MvcOptions
|
var options = new MvcOptions();
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes,
|
|
||||||
};
|
|
||||||
foreach (var formatter in inputFormatters ?? CreateInputFormatters())
|
foreach (var formatter in inputFormatters ?? CreateInputFormatters())
|
||||||
{
|
{
|
||||||
options.InputFormatters.Add(formatter);
|
options.InputFormatters.Add(formatter);
|
||||||
|
|
|
||||||
|
|
@ -169,19 +169,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
loggerFactory);
|
loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ApplicationModelProviderContext GetContext(
|
|
||||||
Type type,
|
|
||||||
IModelMetadataProvider modelMetadataProvider = null)
|
|
||||||
{
|
|
||||||
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
|
|
||||||
var mvcOptions = Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true });
|
|
||||||
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
|
|
||||||
var provider = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
|
||||||
provider.OnProvidersExecuting(context);
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestApiController : ControllerBase
|
private class TestApiController : ControllerBase
|
||||||
{
|
{
|
||||||
public IActionResult TestAction(object value) => null;
|
public IActionResult TestAction(object value) => null;
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
IModelMetadataProvider modelMetadataProvider = null)
|
IModelMetadataProvider modelMetadataProvider = null)
|
||||||
{
|
{
|
||||||
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
|
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
|
||||||
var mvcOptions = Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true });
|
var mvcOptions = Options.Create(new MvcOptions());
|
||||||
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
|
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
|
||||||
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
||||||
convention.OnProvidersExecuting(context);
|
convention.OnProvidersExecuting(context);
|
||||||
|
|
@ -68,12 +68,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ControllerModel GetControllerModel(Type controllerType)
|
|
||||||
{
|
|
||||||
var context = GetContext(controllerType);
|
|
||||||
return Assert.Single(context.Result.Controllers);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ActionModel GetActionModel(Type controllerType, string actionName)
|
private static ActionModel GetActionModel(Type controllerType, string actionName)
|
||||||
{
|
{
|
||||||
var context = GetContext(controllerType);
|
var context = GetContext(controllerType);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new TestApplicationModelProvider(
|
var builder = new TestApplicationModelProvider(
|
||||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
new MvcOptions(),
|
||||||
TestModelMetadataProvider.CreateDefaultProvider());
|
TestModelMetadataProvider.CreateDefaultProvider());
|
||||||
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
||||||
|
|
||||||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new TestApplicationModelProvider(
|
var builder = new TestApplicationModelProvider(
|
||||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
new MvcOptions(),
|
||||||
TestModelMetadataProvider.CreateDefaultProvider());
|
TestModelMetadataProvider.CreateDefaultProvider());
|
||||||
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
||||||
|
|
||||||
|
|
@ -191,57 +191,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_WithLegacyValidationBehavior()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var builder = new TestApplicationModelProvider(
|
|
||||||
new MvcOptions(),
|
|
||||||
TestModelMetadataProvider.CreateDefaultProvider());
|
|
||||||
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]
|
[Fact]
|
||||||
public void OnProvidersExecuting_InfersFormFileSourceForTypesAssignableFromIEnumerableOfFormFiles()
|
public void OnProvidersExecuting_InfersFormFileSourceForTypesAssignableFromIEnumerableOfFormFiles()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new TestApplicationModelProvider(
|
var builder = new TestApplicationModelProvider(
|
||||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
new MvcOptions(),
|
||||||
TestModelMetadataProvider.CreateDefaultProvider());
|
TestModelMetadataProvider.CreateDefaultProvider());
|
||||||
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
||||||
|
|
||||||
|
|
@ -286,7 +241,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_ReadFromModelMetadata()
|
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_ReadFromModelMetadata()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var options = new MvcOptions { AllowValidatingTopLevelNodes = true };
|
var options = new MvcOptions();
|
||||||
var detailsProvider = new BindingSourceMetadataProvider(typeof(Guid), BindingSource.Special);
|
var detailsProvider = new BindingSourceMetadataProvider(typeof(Guid), BindingSource.Special);
|
||||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
|
||||||
|
|
||||||
|
|
@ -1822,9 +1777,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
private class TestApplicationModelProvider : DefaultApplicationModelProvider
|
private class TestApplicationModelProvider : DefaultApplicationModelProvider
|
||||||
{
|
{
|
||||||
public TestApplicationModelProvider()
|
public TestApplicationModelProvider()
|
||||||
: this(
|
: this(new MvcOptions(), new EmptyModelMetadataProvider())
|
||||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
|
||||||
new EmptyModelMetadataProvider())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -468,22 +468,6 @@ Environment.NewLine + "int b";
|
||||||
Assert.Same(BindingSource.Body, result);
|
Assert.Same(BindingSource.Body, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void InferBindingSourceForParameter_ReturnsQueryForCollectionOfSimpleTypes_WhenAllowInferringBindingSourceForCollectionTypesAsFromQueryIsSet()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionName = nameof(ParameterBindingController.CollectionOfSimpleTypes);
|
|
||||||
var parameter = GetParameterModel(typeof(ParameterBindingController), actionName);
|
|
||||||
var convention = GetConvention();
|
|
||||||
convention.AllowInferringBindingSourceForCollectionTypesAsFromQuery = true;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = convention.InferBindingSourceForParameter(parameter);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Same(BindingSource.Query, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void InferBindingSourceForParameter_ReturnsBodyForCollectionOfComplexTypes()
|
public void InferBindingSourceForParameter_ReturnsBodyForCollectionOfComplexTypes()
|
||||||
{
|
{
|
||||||
|
|
@ -499,22 +483,6 @@ Environment.NewLine + "int b";
|
||||||
Assert.Same(BindingSource.Body, result);
|
Assert.Same(BindingSource.Body, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void InferBindingSourceForParameter_ReturnsQueryForCollectionOfComplexTypes_WhenAllowInferringBindingSourceForCollectionTypesAsFromQueryIsSet()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionName = nameof(ParameterBindingController.CollectionOfComplexTypes);
|
|
||||||
var parameter = GetParameterModel(typeof(ParameterBindingController), actionName);
|
|
||||||
var convention = GetConvention();
|
|
||||||
convention.AllowInferringBindingSourceForCollectionTypesAsFromQuery = true;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = convention.InferBindingSourceForParameter(parameter);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Same(BindingSource.Query, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void PreservesBindingSourceInference_ForFromQueryParameter_WithDefaultName()
|
public void PreservesBindingSourceInference_ForFromQueryParameter_WithDefaultName()
|
||||||
{
|
{
|
||||||
|
|
@ -782,7 +750,7 @@ Environment.NewLine + "int b";
|
||||||
IModelMetadataProvider modelMetadataProvider = null)
|
IModelMetadataProvider modelMetadataProvider = null)
|
||||||
{
|
{
|
||||||
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
|
var context = new ApplicationModelProviderContext(new[] { type.GetTypeInfo() });
|
||||||
var mvcOptions = Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true });
|
var mvcOptions = Options.Create(new MvcOptions());
|
||||||
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
|
modelMetadataProvider = modelMetadataProvider ?? new EmptyModelMetadataProvider();
|
||||||
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
||||||
convention.OnProvidersExecuting(context);
|
convention.OnProvidersExecuting(context);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
||||||
|
|
||||||
// The type 'AuthorizeFilter' is both a filter by itself and also a filter factory.
|
// The type 'AuthorizeFilter' is both a filter by itself and also a filter factory.
|
||||||
// The default filter provider first checks if a type is a filter factory and creates an instance of
|
// The default filter provider first checks if a type is a filter factory and creates an instance of
|
||||||
// this filter.
|
// this filter.
|
||||||
|
|
@ -38,6 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
var filterFactory = authorizeFilterFactory as IFilterFactory;
|
var filterFactory = authorizeFilterFactory as IFilterFactory;
|
||||||
var authorizeFilter = (AuthorizeFilter)filterFactory.CreateInstance(
|
var authorizeFilter = (AuthorizeFilter)filterFactory.CreateInstance(
|
||||||
authorizationContext.HttpContext.RequestServices);
|
authorizationContext.HttpContext.RequestServices);
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
|
@ -52,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
||||||
var authorizationContext = GetAuthorizationContext();
|
var authorizationContext = GetAuthorizationContext();
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
||||||
"IAuthorizationPolicyProvider.";
|
"IAuthorizationPolicyProvider.";
|
||||||
|
|
||||||
|
|
@ -67,6 +70,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
||||||
var authorizationContext = GetAuthorizationContext();
|
var authorizationContext = GetAuthorizationContext();
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
||||||
"IAuthorizationPolicyProvider.";
|
"IAuthorizationPolicyProvider.";
|
||||||
|
|
||||||
|
|
@ -101,6 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
.Callback(() => getPolicyCount++);
|
.Callback(() => getPolicyCount++);
|
||||||
var authorizeFilter = new AuthorizeFilter(policyProvider.Object, new AuthorizeAttribute[] { new AuthorizeAttribute("whatever") });
|
var authorizeFilter = new AuthorizeFilter(policyProvider.Object, new AuthorizeAttribute[] { new AuthorizeAttribute("whatever") });
|
||||||
var authorizationContext = GetAuthorizationContext();
|
var authorizationContext = GetAuthorizationContext();
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
|
@ -153,6 +158,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
|
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
|
@ -223,8 +229,10 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
|
|
||||||
private class TestPolicyProvider : IAuthorizationPolicyProvider
|
private class TestPolicyProvider : IAuthorizationPolicyProvider
|
||||||
{
|
{
|
||||||
private AuthorizationPolicy _true = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
|
private readonly AuthorizationPolicy _true =
|
||||||
private AuthorizationPolicy _false = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build();
|
new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
|
||||||
|
private readonly AuthorizationPolicy _false =
|
||||||
|
new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build();
|
||||||
|
|
||||||
public int GetPolicyCalls = 0;
|
public int GetPolicyCalls = 0;
|
||||||
|
|
||||||
|
|
@ -250,7 +258,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
new AuthorizeAttribute { Policy = "true"},
|
new AuthorizeAttribute { Policy = "true"},
|
||||||
new AuthorizeAttribute { Policy = "false"}
|
new AuthorizeAttribute { Policy = "false"}
|
||||||
});
|
});
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
var authorizationContext = GetAuthorizationContext(anonymous: false);
|
||||||
// Effective policy should fail, if both are combined
|
// Effective policy should fail, if both are combined
|
||||||
authorizationContext.Filters.Add(authorizeFilter);
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||||
|
|
@ -274,7 +282,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
new AuthorizeAttribute { Policy = "true"},
|
new AuthorizeAttribute { Policy = "true"},
|
||||||
new AuthorizeAttribute { Policy = "false"}
|
new AuthorizeAttribute { Policy = "false"}
|
||||||
});
|
});
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
var authorizationContext = GetAuthorizationContext(anonymous: false);
|
||||||
// Effective policy should fail, if both are combined
|
// Effective policy should fail, if both are combined
|
||||||
authorizationContext.Filters.Add(authorizeFilter);
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||||
|
|
@ -304,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
var authorizationContext = GetAuthorizationContext(anonymous: false);
|
||||||
// Effective policy should fail, if both are combined
|
// Effective policy should fail, if both are combined
|
||||||
authorizationContext.Filters.Add(authorizeFilter);
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||||
|
|
@ -322,7 +330,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
var authorizationContext = GetAuthorizationContext(anonymous: false);
|
||||||
// Effective policy should fail, if both are combined
|
// Effective policy should fail, if both are combined
|
||||||
authorizationContext.Filters.Add(authorizeFilter);
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||||
|
|
@ -340,7 +348,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
var authorizationContext = GetAuthorizationContext(anonymous: false);
|
||||||
// Effective policy should fail, if both are combined
|
// Effective policy should fail, if both are combined
|
||||||
authorizationContext.Filters.Add(authorizeFilter);
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
authorizationContext.Filters.Add(new DerivedAuthorizeFilter());
|
authorizationContext.Filters.Add(new DerivedAuthorizeFilter());
|
||||||
|
|
@ -381,6 +389,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
// Arrange
|
// Arrange
|
||||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("Wut").Build());
|
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("Wut").Build());
|
||||||
var authorizationContext = GetAuthorizationContext();
|
var authorizationContext = GetAuthorizationContext();
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
|
@ -397,6 +406,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
.RequireClaim("Permission", "CanViewComment")
|
.RequireClaim("Permission", "CanViewComment")
|
||||||
.Build());
|
.Build());
|
||||||
var authorizationContext = GetAuthorizationContext();
|
var authorizationContext = GetAuthorizationContext();
|
||||||
|
authorizationContext.Filters.Add(authorizeFilter);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||||
|
|
@ -532,10 +542,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
serviceCollection.AddSingleton(auth.Object);
|
serviceCollection.AddSingleton(auth.Object);
|
||||||
serviceCollection.AddAuthorization();
|
serviceCollection.AddAuthorization();
|
||||||
serviceCollection.AddAuthorizationPolicyEvaluator();
|
serviceCollection.AddAuthorizationPolicyEvaluator();
|
||||||
if (registerServices != null)
|
registerServices?.Invoke(serviceCollection);
|
||||||
{
|
|
||||||
registerServices(serviceCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
|
@ -557,7 +564,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||||
routeData: new RouteData(),
|
routeData: new RouteData(),
|
||||||
actionDescriptor: new ActionDescriptor());
|
actionDescriptor: new ActionDescriptor());
|
||||||
|
|
||||||
var authorizationContext = new Filters.AuthorizationFilterContext(
|
var authorizationContext = new AuthorizationFilterContext(
|
||||||
actionContext,
|
actionContext,
|
||||||
Enumerable.Empty<IFilterMetadata>().ToList()
|
Enumerable.Empty<IFilterMetadata>().ToList()
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
@ -28,10 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
{
|
{
|
||||||
public class ControllerBinderDelegateProviderTest
|
public class ControllerBinderDelegateProviderTest
|
||||||
{
|
{
|
||||||
private static readonly MvcOptions _options = new MvcOptions
|
private static readonly MvcOptions _options = new MvcOptions();
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
};
|
|
||||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -428,55 +424,6 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||||
controllerContext.ModelState["memberName"].Errors.Single().ErrorMessage);
|
controllerContext.ModelState["memberName"].Errors.Single().ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task CreateBinderDelegate_Delegate_DoesNotCallValidator_IfNotValidatingTopLevelNodes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionDescriptor = GetActionDescriptor();
|
|
||||||
actionDescriptor.Parameters.Add(
|
|
||||||
new ControllerParameterDescriptor
|
|
||||||
{
|
|
||||||
Name = "foo",
|
|
||||||
ParameterType = typeof(object),
|
|
||||||
ParameterInfo = ParameterInfos.CustomValidationParameterInfo
|
|
||||||
});
|
|
||||||
|
|
||||||
var controllerContext = GetControllerContext(actionDescriptor);
|
|
||||||
var factory = GetModelBinderFactory("Hello");
|
|
||||||
|
|
||||||
var mockValidator = new Mock<IModelValidator>();
|
|
||||||
mockValidator
|
|
||||||
.Setup(o => o.Validate(It.IsAny<ModelValidationContext>()))
|
|
||||||
.Returns(new[] { new ModelValidationResult("memberName", "some message") });
|
|
||||||
|
|
||||||
// Do not set AllowValidatingTopLevelNodes.
|
|
||||||
var mvcOptions = new MvcOptions();
|
|
||||||
|
|
||||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
||||||
var parameterBinder = new ParameterBinder(
|
|
||||||
modelMetadataProvider,
|
|
||||||
factory,
|
|
||||||
GetObjectValidator(modelMetadataProvider, GetModelValidatorProvider(mockValidator.Object)),
|
|
||||||
Options.Create(mvcOptions),
|
|
||||||
NullLoggerFactory.Instance);
|
|
||||||
var controller = new TestController();
|
|
||||||
var arguments = new Dictionary<string, object>(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
|
|
||||||
parameterBinder,
|
|
||||||
factory,
|
|
||||||
modelMetadataProvider,
|
|
||||||
actionDescriptor,
|
|
||||||
mvcOptions);
|
|
||||||
|
|
||||||
await binderDelegate(controllerContext, controller, arguments);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(controllerContext.ModelState.IsValid);
|
|
||||||
mockValidator.Verify(o => o.Validate(It.IsAny<ModelValidationContext>()), Times.Never());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CreateBinderDelegate_Delegate_DoesNotCallValidator_IfModelBinderFails()
|
public async Task CreateBinderDelegate_Delegate_DoesNotCallValidator_IfModelBinderFails()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
@ -18,9 +16,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void Configure_AssignsInvalidModelStateResponseFactory()
|
public void Configure_AssignsInvalidModelStateResponseFactory()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Options.Create(new MvcCompatibilityOptions()));
|
|
||||||
var options = new ApiBehaviorOptions();
|
var options = new ApiBehaviorOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -35,9 +31,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new[] { 400, 401, 403, 404, 406, 409, 415, 422, };
|
var expected = new[] { 400, 401, 403, 404, 406, 409, 415, 422, };
|
||||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Options.Create(new MvcCompatibilityOptions()));
|
|
||||||
var options = new ApiBehaviorOptions();
|
var options = new ApiBehaviorOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -51,9 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void PostConfigure_SetProblemDetailsModelStateResponseFactory()
|
public void PostConfigure_SetProblemDetailsModelStateResponseFactory()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Options.Create(new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Latest }));
|
|
||||||
var options = new ApiBehaviorOptions();
|
var options = new ApiBehaviorOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -68,9 +60,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void PostConfigure_DoesNotSetProblemDetailsFactory_IfValueWasModified()
|
public void PostConfigure_DoesNotSetProblemDetailsFactory_IfValueWasModified()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Options.Create(new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Latest }));
|
|
||||||
var options = new ApiBehaviorOptions();
|
var options = new ApiBehaviorOptions();
|
||||||
Func<ActionContext, IActionResult> expected = _ => null;
|
Func<ActionContext, IActionResult> expected = _ => null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
new[] { new DefaultFilterProvider() });
|
new[] { new DefaultFilterProvider() });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var cacheEntry1 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
var (cacheEntry, filters) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||||
var cacheEntry2 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
var (cacheEntry2, filters2) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(cacheEntry1.filters, cacheEntry2.filters);
|
Assert.Equal(filters, filters2);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -54,11 +54,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
new[] { new DefaultFilterProvider() });
|
new[] { new DefaultFilterProvider() });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var cacheEntry1 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
var (cacheEntry, filters) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||||
var cacheEntry2 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
var (cacheEntry2, filters2) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(cacheEntry1.cacheEntry, cacheEntry2.cacheEntry);
|
Assert.Same(cacheEntry, cacheEntry2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestFilter : IFilterMetadata
|
private class TestFilter : IFilterMetadata
|
||||||
|
|
@ -100,10 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
new[] { controllerContext.ActionDescriptor });
|
new[] { controllerContext.ActionDescriptor });
|
||||||
var modelMetadataProvider = new EmptyModelMetadataProvider();
|
var modelMetadataProvider = new EmptyModelMetadataProvider();
|
||||||
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
||||||
var mvcOptions = Options.Create(new MvcOptions
|
var mvcOptions = Options.Create(new MvcOptions());
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return new ControllerActionInvokerCache(
|
return new ControllerActionInvokerCache(
|
||||||
descriptorProvider,
|
descriptorProvider,
|
||||||
|
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
// 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 Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Core.Infrastructure
|
|
||||||
{
|
|
||||||
public class MvcOptionsConfigureCompatibilityOptionsTest
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public void PostConfigure_ConfiguresMaxValidationDepth()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var mvcOptions = new MvcOptions();
|
|
||||||
var mvcCompatibilityOptions = new MvcCompatibilityOptions
|
|
||||||
{
|
|
||||||
CompatibilityVersion = CompatibilityVersion.Version_3_0,
|
|
||||||
};
|
|
||||||
|
|
||||||
var configureOptions = new MvcOptionsConfigureCompatibilityOptions(
|
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Create(mvcCompatibilityOptions));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
configureOptions.PostConfigure(string.Empty, mvcOptions);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(32, mvcOptions.MaxValidationDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void PostConfigure_DoesNotConfiguresMaxValidationDepth_WhenSetToNull()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var mvcOptions = new MvcOptions
|
|
||||||
{
|
|
||||||
MaxValidationDepth = null,
|
|
||||||
};
|
|
||||||
var mvcCompatibilityOptions = new MvcCompatibilityOptions
|
|
||||||
{
|
|
||||||
CompatibilityVersion = CompatibilityVersion.Version_3_0,
|
|
||||||
};
|
|
||||||
|
|
||||||
var configureOptions = new MvcOptionsConfigureCompatibilityOptions(
|
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Create(mvcCompatibilityOptions));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
configureOptions.PostConfigure(string.Empty, mvcOptions);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Null(mvcOptions.MaxValidationDepth);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void PostConfigure_DoesNotConfiguresMaxValidationDepth_WhenSetToValue()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var expected = 13;
|
|
||||||
var mvcOptions = new MvcOptions
|
|
||||||
{
|
|
||||||
MaxValidationDepth = expected,
|
|
||||||
};
|
|
||||||
var mvcCompatibilityOptions = new MvcCompatibilityOptions
|
|
||||||
{
|
|
||||||
CompatibilityVersion = CompatibilityVersion.Version_3_0,
|
|
||||||
};
|
|
||||||
|
|
||||||
var configureOptions = new MvcOptionsConfigureCompatibilityOptions(
|
|
||||||
NullLoggerFactory.Instance,
|
|
||||||
Options.Create(mvcCompatibilityOptions));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
configureOptions.PostConfigure(string.Empty, mvcOptions);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(expected, mvcOptions.MaxValidationDepth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -51,17 +51,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.IsType(typeof(ArrayModelBinder<>).MakeGenericType(modelType.GetElementType()), result);
|
Assert.IsType(typeof(ArrayModelBinder<>).MakeGenericType(modelType.GetElementType()), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(false)]
|
public void Create_ForArrayType_ReturnsBinder()
|
||||||
[InlineData(true)]
|
|
||||||
public void Create_ForArrayType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
|
||||||
bool allowValidatingTopLevelNodes)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new ArrayModelBinderProvider();
|
var provider = new ArrayModelBinderProvider();
|
||||||
|
|
||||||
var context = new TestModelBinderProviderContext(typeof(int[]));
|
var context = new TestModelBinderProviderContext(typeof(int[]));
|
||||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
context.OnCreatingBinder(m =>
|
context.OnCreatingBinder(m =>
|
||||||
{
|
{
|
||||||
Assert.Equal(typeof(int), m.ModelType);
|
Assert.Equal(typeof(int), m.ModelType);
|
||||||
|
|
@ -73,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var binder = Assert.IsType<ArrayModelBinder<int>>(result);
|
var binder = Assert.IsType<ArrayModelBinder<int>>(result);
|
||||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
Assert.True(binder.AllowValidatingTopLevelNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
[InlineData(false, false)]
|
[InlineData(false, false)]
|
||||||
[InlineData(false, true)]
|
[InlineData(false, true)]
|
||||||
[InlineData(true, false)]
|
[InlineData(true, false)]
|
||||||
|
[InlineData(true, true)]
|
||||||
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
||||||
bool allowValidatingTopLevelNodes,
|
bool allowValidatingTopLevelNodes,
|
||||||
bool isBindingRequired)
|
bool isBindingRequired)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var expectedErrorCount = isBindingRequired ? 1 : 0;
|
||||||
var binder = new ArrayModelBinder<string>(
|
var binder = new ArrayModelBinder<string>(
|
||||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||||
NullLoggerFactory.Instance,
|
NullLoggerFactory.Instance,
|
||||||
|
|
@ -81,7 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(Assert.IsType<string[]>(bindingContext.Result.Model));
|
Assert.Empty(Assert.IsType<string[]>(bindingContext.Result.Model));
|
||||||
Assert.True(bindingContext.Result.IsModelSet);
|
Assert.True(bindingContext.Result.IsModelSet);
|
||||||
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -218,30 +220,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IModelBinder CreateIntBinder()
|
|
||||||
{
|
|
||||||
return new StubModelBinder(context =>
|
|
||||||
{
|
|
||||||
var value = context.ValueProvider.GetValue(context.ModelName);
|
|
||||||
if (value != ValueProviderResult.None)
|
|
||||||
{
|
|
||||||
object valueToConvert = null;
|
|
||||||
if (value.Values.Count == 1)
|
|
||||||
{
|
|
||||||
valueToConvert = value.Values[0];
|
|
||||||
}
|
|
||||||
else if (value.Values.Count > 1)
|
|
||||||
{
|
|
||||||
valueToConvert = value.Values.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
var model = ModelBindingHelper.ConvertTo(valueToConvert, context.ModelType, value.Culture);
|
|
||||||
return ModelBindingResult.Success(model);
|
|
||||||
}
|
|
||||||
return ModelBindingResult.Failed();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DefaultModelBindingContext GetBindingContext(IValueProvider valueProvider)
|
private static DefaultModelBindingContext GetBindingContext(IValueProvider valueProvider)
|
||||||
{
|
{
|
||||||
var bindingContext = CreateContext();
|
var bindingContext = CreateContext();
|
||||||
|
|
@ -277,4 +255,3 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,17 +66,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.IsType<CollectionModelBinder<int>>(result);
|
Assert.IsType<CollectionModelBinder<int>>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(false)]
|
public void Create_ForSupportedType_ReturnsBinder()
|
||||||
[InlineData(true)]
|
|
||||||
public void Create_ForSupportedType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
|
||||||
bool allowValidatingTopLevelNodes)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new CollectionModelBinderProvider();
|
var provider = new CollectionModelBinderProvider();
|
||||||
|
|
||||||
var context = new TestModelBinderProviderContext(typeof(List<int>));
|
var context = new TestModelBinderProviderContext(typeof(List<int>));
|
||||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
context.OnCreatingBinder(m =>
|
context.OnCreatingBinder(m =>
|
||||||
{
|
{
|
||||||
Assert.Equal(typeof(int), m.ModelType);
|
Assert.Equal(typeof(int), m.ModelType);
|
||||||
|
|
@ -88,7 +84,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var binder = Assert.IsType<CollectionModelBinder<int>>(result);
|
var binder = Assert.IsType<CollectionModelBinder<int>>(result);
|
||||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
Assert.True(binder.AllowValidatingTopLevelNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Person
|
private class Person
|
||||||
|
|
|
||||||
|
|
@ -55,17 +55,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.IsType<ComplexTypeModelBinder>(result);
|
Assert.IsType<ComplexTypeModelBinder>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(false)]
|
public void Create_ForSupportedType_ReturnsBinder()
|
||||||
[InlineData(true)]
|
|
||||||
public void Create_ForSupportedType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
|
||||||
bool allowValidatingTopLevelNodes)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new ComplexTypeModelBinderProvider();
|
var provider = new ComplexTypeModelBinderProvider();
|
||||||
|
|
||||||
var context = new TestModelBinderProviderContext(typeof(Person));
|
var context = new TestModelBinderProviderContext(typeof(Person));
|
||||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
context.OnCreatingBinder(m =>
|
context.OnCreatingBinder(m =>
|
||||||
{
|
{
|
||||||
if (m.ModelType == typeof(int) || m.ModelType == typeof(string))
|
if (m.ModelType == typeof(int) || m.ModelType == typeof(string))
|
||||||
|
|
@ -83,8 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var result = provider.GetBinder(context);
|
var result = provider.GetBinder(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var binder = Assert.IsType<ComplexTypeModelBinder>(result);
|
Assert.IsType<ComplexTypeModelBinder>(result);
|
||||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Person
|
private class Person
|
||||||
|
|
|
||||||
|
|
@ -57,40 +57,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var result = provider.GetBinder(context);
|
var result = provider.GetBinder(context);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsType<DictionaryModelBinder<string, int>>(result);
|
var binder = Assert.IsType<DictionaryModelBinder<string, int>>(result);
|
||||||
}
|
Assert.False(binder.AllowValidatingTopLevelNodes); // work done in DictionaryModelBinder.
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData(false)]
|
|
||||||
[InlineData(true)]
|
|
||||||
public void Create_ForDictionaryType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
|
||||||
bool allowValidatingTopLevelNodes)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new DictionaryModelBinderProvider();
|
|
||||||
|
|
||||||
var context = new TestModelBinderProviderContext(typeof(Dictionary<string, string>));
|
|
||||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
|
||||||
context.OnCreatingBinder(m =>
|
|
||||||
{
|
|
||||||
if (m.ModelType == typeof(KeyValuePair<string, string>) || m.ModelType == typeof(string))
|
|
||||||
{
|
|
||||||
return Mock.Of<IModelBinder>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.False(true, "Not the right model type");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = provider.GetBinder(context);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var binder = Assert.IsType<DictionaryModelBinder<string, string>>(result);
|
|
||||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
|
||||||
Assert.False(((CollectionModelBinder<KeyValuePair<string, string>>)binder).AllowValidatingTopLevelNodes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Person
|
private class Person
|
||||||
|
|
|
||||||
|
|
@ -349,11 +349,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
[InlineData(false, false)]
|
[InlineData(false, false)]
|
||||||
[InlineData(false, true)]
|
[InlineData(false, true)]
|
||||||
[InlineData(true, false)]
|
[InlineData(true, false)]
|
||||||
|
[InlineData(true, true)]
|
||||||
public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
||||||
bool allowValidatingTopLevelNodes,
|
bool allowValidatingTopLevelNodes,
|
||||||
bool isBindingRequired)
|
bool isBindingRequired)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var expectedErrorCount = isBindingRequired ? 1 : 0;
|
||||||
var binder = new DictionaryModelBinder<string, string>(
|
var binder = new DictionaryModelBinder<string, string>(
|
||||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||||
|
|
@ -383,7 +385,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Empty(Assert.IsType<Dictionary<string, string>>(bindingContext.Result.Model));
|
Assert.Empty(Assert.IsType<Dictionary<string, string>>(bindingContext.Result.Model));
|
||||||
Assert.True(bindingContext.Result.IsModelSet);
|
Assert.True(bindingContext.Result.IsModelSet);
|
||||||
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -14,55 +14,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
public class HeaderModelBinderProviderTest
|
public class HeaderModelBinderProviderTest
|
||||||
{
|
{
|
||||||
[Theory]
|
|
||||||
[InlineData(typeof(string))]
|
|
||||||
[InlineData(typeof(string[]))]
|
|
||||||
[InlineData(typeof(List<string>))]
|
|
||||||
public void Create_WhenBindingSourceIsFromHeader_ReturnsBinder_ForStringTypes_And_CompatVersion_2_0(
|
|
||||||
Type modelType)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new HeaderModelBinderProvider();
|
|
||||||
var testBinder = Mock.Of<IModelBinder>();
|
|
||||||
var context = GetTestModelBinderProviderContext(
|
|
||||||
modelType,
|
|
||||||
allowBindingHeaderValuesToNonStringModelTypes: false);
|
|
||||||
context.BindingInfo.BindingSource = BindingSource.Header;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = provider.GetBinder(context);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.IsType<HeaderModelBinder>(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineData(typeof(int))]
|
|
||||||
[InlineData(typeof(int?))]
|
|
||||||
[InlineData(typeof(IEnumerable<int>))]
|
|
||||||
[InlineData(typeof(double))]
|
|
||||||
[InlineData(typeof(double?))]
|
|
||||||
[InlineData(typeof(IEnumerable<double>))]
|
|
||||||
[InlineData(typeof(CarEnumType))]
|
|
||||||
[InlineData(typeof(CarEnumType?))]
|
|
||||||
[InlineData(typeof(IEnumerable<CarEnumType>))]
|
|
||||||
public void Create_WhenBindingSourceIsFromHeader_ReturnsNull_ForNonStringTypes_And_CompatVersion_2_0(
|
|
||||||
Type modelType)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new HeaderModelBinderProvider();
|
|
||||||
var context = GetTestModelBinderProviderContext(
|
|
||||||
modelType,
|
|
||||||
allowBindingHeaderValuesToNonStringModelTypes: false);
|
|
||||||
context.BindingInfo.BindingSource = BindingSource.Header;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = provider.GetBinder(context);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Null(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TheoryData<BindingSource> NonHeaderBindingSources
|
public static TheoryData<BindingSource> NonHeaderBindingSources
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -227,13 +178,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.Null(result);
|
Assert.Null(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestModelBinderProviderContext GetTestModelBinderProviderContext(
|
private TestModelBinderProviderContext GetTestModelBinderProviderContext(Type modelType)
|
||||||
Type modelType,
|
|
||||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
|
||||||
{
|
{
|
||||||
var context = new TestModelBinderProviderContext(modelType);
|
var context = new TestModelBinderProviderContext(modelType);
|
||||||
var options = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
var options = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||||
options.AllowBindingHeaderValuesToNonStringModelTypes = allowBindingHeaderValuesToNonStringModelTypes;
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var data = new TheoryData<HeaderModelBinder>();
|
var data = new TheoryData<HeaderModelBinder>
|
||||||
|
{
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
data.Add(new HeaderModelBinder());
|
new HeaderModelBinder(),
|
||||||
#pragma warning restore CS0618
|
#pragma warning restore CS0618
|
||||||
data.Add(new HeaderModelBinder(NullLoggerFactory.Instance));
|
new HeaderModelBinder(NullLoggerFactory.Instance),
|
||||||
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,11 +178,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(typeof(CarType?), null)]
|
[InlineData(typeof(CarType?))]
|
||||||
[InlineData(typeof(int?), null)]
|
[InlineData(typeof(int?))]
|
||||||
public async Task HeaderBinder_DoesNotSetModel_ForHeaderNotPresentOnRequest(
|
public async Task HeaderBinder_DoesNotSetModel_ForHeaderNotPresentOnRequest(Type modelType)
|
||||||
Type modelType,
|
|
||||||
object expectedModel)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var bindingContext = CreateContext(modelType);
|
var bindingContext = CreateContext(modelType);
|
||||||
|
|
@ -194,11 +195,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(typeof(string[]), null)]
|
[InlineData(typeof(string[]))]
|
||||||
[InlineData(typeof(IEnumerable<string>), null)]
|
[InlineData(typeof(IEnumerable<string>))]
|
||||||
public async Task HeaderBinder_DoesNotCreateEmptyCollection_ForNonTopLevelObjects(
|
public async Task HeaderBinder_DoesNotCreateEmptyCollection_ForNonTopLevelObjects(Type modelType)
|
||||||
Type modelType,
|
|
||||||
object expectedModel)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var bindingContext = CreateContext(modelType);
|
var bindingContext = CreateContext(modelType);
|
||||||
|
|
@ -344,30 +343,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.Equal($"The value '{headerValues[1]}' is not valid.", entry.Errors[1].ErrorMessage);
|
Assert.Equal($"The value '{headerValues[1]}' is not valid.", entry.Errors[1].ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DefaultModelBindingContext CreateContext(
|
private static DefaultModelBindingContext CreateContext(Type modelType)
|
||||||
Type modelType,
|
|
||||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
|
||||||
{
|
{
|
||||||
return CreateContext(
|
return CreateContext(metadata: GetMetadataForType(modelType), valueProvider: null);
|
||||||
metadata: GetMetadataForType(modelType),
|
|
||||||
valueProvider: null,
|
|
||||||
allowBindingHeaderValuesToNonStringModelTypes: allowBindingHeaderValuesToNonStringModelTypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DefaultModelBindingContext CreateContext(
|
private static DefaultModelBindingContext CreateContext(
|
||||||
ModelMetadata metadata,
|
ModelMetadata metadata,
|
||||||
IValueProvider valueProvider = null,
|
IValueProvider valueProvider = null)
|
||||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
|
||||||
{
|
{
|
||||||
if (valueProvider == null)
|
if (valueProvider == null)
|
||||||
{
|
{
|
||||||
valueProvider = Mock.Of<IValueProvider>();
|
valueProvider = Mock.Of<IValueProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = new MvcOptions()
|
var options = new MvcOptions();
|
||||||
{
|
|
||||||
AllowBindingHeaderValuesToNonStringModelTypes = allowBindingHeaderValuesToNonStringModelTypes
|
|
||||||
};
|
|
||||||
var setup = new MvcCoreMvcOptionsSetup(new TestHttpRequestStreamReaderFactory());
|
var setup = new MvcCoreMvcOptionsSetup(new TestHttpRequestStreamReaderFactory());
|
||||||
setup.Configure(options);
|
setup.Configure(options);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
public class ParameterBinderTest
|
public class ParameterBinderTest
|
||||||
{
|
{
|
||||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(new MvcOptions
|
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(new MvcOptions());
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
public static TheoryData BindModelAsyncData
|
public static TheoryData BindModelAsyncData
|
||||||
{
|
{
|
||||||
|
|
@ -211,37 +208,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
actionContext.ModelState.Single().Value.Errors.Single().ErrorMessage);
|
actionContext.ModelState.Single().Value.Errors.Single().ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task BindModelAsync_DoesNotEnforceTopLevelBindRequired_IfNotValidatingTopLevelNodes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionContext = GetControllerContext();
|
|
||||||
|
|
||||||
var mockModelMetadata = CreateMockModelMetadata();
|
|
||||||
mockModelMetadata.Setup(o => o.IsBindingRequired).Returns(true);
|
|
||||||
|
|
||||||
// Bind attribute errors are phrased in terms of the model name, not display name
|
|
||||||
mockModelMetadata.Setup(o => o.DisplayName).Returns("Ignored Display Name");
|
|
||||||
|
|
||||||
// Do not set AllowValidatingTopLevelNodes.
|
|
||||||
var optionsAccessor = Options.Create(new MvcOptions());
|
|
||||||
var parameterBinder = CreateParameterBinder(mockModelMetadata.Object, optionsAccessor: optionsAccessor);
|
|
||||||
var modelBindingResult = ModelBindingResult.Failed();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await parameterBinder.BindModelAsync(
|
|
||||||
actionContext,
|
|
||||||
CreateMockModelBinder(modelBindingResult),
|
|
||||||
CreateMockValueProvider(),
|
|
||||||
new ParameterDescriptor { Name = "myParam", ParameterType = typeof(Person) },
|
|
||||||
mockModelMetadata.Object,
|
|
||||||
"ignoredvalue");
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(actionContext.ModelState.IsValid);
|
|
||||||
Assert.Empty(actionContext.ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task BindModelAsync_EnforcesTopLevelRequired()
|
public async Task BindModelAsync_EnforcesTopLevelRequired()
|
||||||
{
|
{
|
||||||
|
|
@ -280,43 +246,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
actionContext.ModelState.Single().Value.Errors.Single().ErrorMessage);
|
actionContext.ModelState.Single().Value.Errors.Single().ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task BindModelAsync_DoesNotEnforceTopLevelRequired_IfNotValidatingTopLevelNodes()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionContext = GetControllerContext();
|
|
||||||
var mockModelMetadata = CreateMockModelMetadata();
|
|
||||||
mockModelMetadata.Setup(o => o.IsRequired).Returns(true);
|
|
||||||
mockModelMetadata.Setup(o => o.DisplayName).Returns("My Display Name");
|
|
||||||
mockModelMetadata.Setup(o => o.ValidatorMetadata).Returns(new[]
|
|
||||||
{
|
|
||||||
new RequiredAttribute()
|
|
||||||
});
|
|
||||||
|
|
||||||
var validator = new DataAnnotationsModelValidator(
|
|
||||||
new ValidationAttributeAdapterProvider(),
|
|
||||||
new RequiredAttribute(),
|
|
||||||
stringLocalizer: null);
|
|
||||||
|
|
||||||
// Do not set AllowValidatingTopLevelNodes.
|
|
||||||
var optionsAccessor = Options.Create(new MvcOptions());
|
|
||||||
var parameterBinder = CreateParameterBinder(mockModelMetadata.Object, validator, optionsAccessor);
|
|
||||||
var modelBindingResult = ModelBindingResult.Success(null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await parameterBinder.BindModelAsync(
|
|
||||||
actionContext,
|
|
||||||
CreateMockModelBinder(modelBindingResult),
|
|
||||||
CreateMockValueProvider(),
|
|
||||||
new ParameterDescriptor { Name = "myParam", ParameterType = typeof(Person) },
|
|
||||||
mockModelMetadata.Object,
|
|
||||||
"ignoredvalue");
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(actionContext.ModelState.IsValid);
|
|
||||||
Assert.Empty(actionContext.ModelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TheoryData<RequiredAttribute, ParameterDescriptor, ModelMetadata> EnforcesTopLevelRequiredDataSet
|
public static TheoryData<RequiredAttribute, ParameterDescriptor, ModelMetadata> EnforcesTopLevelRequiredDataSet
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -598,17 +598,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ReadAsync_DefaultOptions_DoesNotWrapJsonInputExceptions()
|
public async Task ReadAsync_DoNotAllowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var formatter = new JsonInputFormatter(
|
var formatter = CreateFormatter(allowInputFormatterExceptionMessages: false);
|
||||||
GetLogger(),
|
|
||||||
_serializerSettings,
|
|
||||||
ArrayPool<char>.Shared,
|
|
||||||
_objectPoolProvider,
|
|
||||||
new MvcOptions(),
|
|
||||||
new MvcJsonOptions());
|
|
||||||
|
|
||||||
var contentBytes = Encoding.UTF8.GetBytes("{");
|
var contentBytes = Encoding.UTF8.GetBytes("{");
|
||||||
var httpContext = GetHttpContext(contentBytes);
|
var httpContext = GetHttpContext(contentBytes);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Administration/EitherCookie");
|
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Administration/EitherCookie");
|
||||||
request.Headers.Add("Cookie", cookie2);
|
request.Headers.Add("Cookie", cookie2);
|
||||||
|
|
||||||
// Act 2: Will succeed because, with AllowCombiningAuthorizeFilters true, [Authorize] allows either cookie.
|
// Act 2: Will succeed because [Authorize] allows either cookie.
|
||||||
response = await Client.SendAsync(request);
|
response = await Client.SendAsync(request);
|
||||||
|
|
||||||
// Assert 2
|
// Assert 2
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
|
|
||||||
var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ControllerActionDescriptor());
|
var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ControllerActionDescriptor());
|
||||||
|
|
||||||
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, action.Filters);
|
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, new[] { authorizeFilter });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await authorizeFilter.OnAuthorizationAsync(authorizationFilterContext);
|
await authorizeFilter.OnAuthorizationAsync(authorizationFilterContext);
|
||||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
var authorizeData = action.Attributes.OfType<AuthorizeAttribute>();
|
var authorizeData = action.Attributes.OfType<AuthorizeAttribute>();
|
||||||
var authorizeFilter = new AuthorizeFilter(policyProvider, authorizeData);
|
var authorizeFilter = new AuthorizeFilter(policyProvider, authorizeData);
|
||||||
|
|
||||||
var actionContext = new ActionContext(GetHttpContext(combineAuthorize: true), new RouteData(), new ControllerActionDescriptor());
|
var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ControllerActionDescriptor());
|
||||||
|
|
||||||
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, action.Filters);
|
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, action.Filters);
|
||||||
|
|
||||||
|
|
@ -89,11 +89,13 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
Assert.Equal(4, policyProvider.GetPolicyCount);
|
Assert.Equal(4, policyProvider.GetPolicyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HttpContext GetHttpContext(bool combineAuthorize = false)
|
private HttpContext GetHttpContext()
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
RequestServices = GetServices()
|
||||||
|
};
|
||||||
|
|
||||||
httpContext.RequestServices = GetServices(combineAuthorize);
|
|
||||||
return httpContext;
|
return httpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,11 +110,11 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceProvider GetServices(bool combineAuthorize)
|
private static IServiceProvider GetServices()
|
||||||
{
|
{
|
||||||
var serviceCollection = new ServiceCollection();
|
var serviceCollection = new ServiceCollection();
|
||||||
serviceCollection.AddAuthorization();
|
serviceCollection.AddAuthorization();
|
||||||
serviceCollection.AddMvc(o => o.AllowCombiningAuthorizeFilters = combineAuthorize);
|
serviceCollection.AddMvc();
|
||||||
serviceCollection
|
serviceCollection
|
||||||
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
|
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
|
||||||
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>()
|
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>()
|
||||||
|
|
|
||||||
|
|
@ -189,51 +189,6 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
Assert.NotNull(entry.RawValue); // Value is set by test model binder, no need to validate it.
|
Assert.NotNull(entry.RawValue); // Value is set by test model binder, no need to validate it.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the metadata is honored when a [ModelBinder] attribute is associated with an action parameter's
|
|
||||||
// type. This should behave identically to such an attribute on an action parameter. (Tests such as
|
|
||||||
// BindParameter_WithData_WithPrefix_GetsBound cover associating [ModelBinder] with an action parameter.)
|
|
||||||
//
|
|
||||||
// This is a regression test for aspnet/Mvc#4652
|
|
||||||
[Theory]
|
|
||||||
[MemberData(nameof(NullAndEmptyBindingInfo))]
|
|
||||||
public async Task BinderTypeOnParameterType_WithDataEmptyPrefixAndVersion20_GetsBound(
|
|
||||||
BindingInfo bindingInfo)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var testContext = ModelBindingTestHelper.GetTestContext(
|
|
||||||
// ParameterBinder will use ModelMetadata for typeof(Address), not Parameter1's ParameterInfo.
|
|
||||||
updateOptions: options => options.AllowValidatingTopLevelNodes = false);
|
|
||||||
|
|
||||||
var modelState = testContext.ModelState;
|
|
||||||
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(testContext.HttpContext.RequestServices);
|
|
||||||
var parameter = new ParameterDescriptor
|
|
||||||
{
|
|
||||||
Name = "Parameter1",
|
|
||||||
BindingInfo = bindingInfo,
|
|
||||||
ParameterType = typeof(Address),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
// ModelBindingResult
|
|
||||||
Assert.True(modelBindingResult.IsModelSet);
|
|
||||||
|
|
||||||
// Model
|
|
||||||
var address = Assert.IsType<Address>(modelBindingResult.Model);
|
|
||||||
Assert.Equal("SomeStreet", address.Street);
|
|
||||||
|
|
||||||
// ModelState
|
|
||||||
Assert.True(modelState.IsValid);
|
|
||||||
var kvp = Assert.Single(modelState);
|
|
||||||
Assert.Equal("Street", kvp.Key);
|
|
||||||
var entry = kvp.Value;
|
|
||||||
Assert.NotNull(entry);
|
|
||||||
Assert.Equal(ModelValidationState.Valid, entry.ValidationState);
|
|
||||||
Assert.NotNull(entry.RawValue); // Value is set by test model binder, no need to validate it.
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Person3
|
private class Person3
|
||||||
{
|
{
|
||||||
[ModelBinder(BinderType = typeof(Address3ModelBinder))]
|
[ModelBinder(BinderType = typeof(Address3ModelBinder))]
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
}
|
}
|
||||||
|
|
||||||
ModelMetadata metadata;
|
ModelMetadata metadata;
|
||||||
if (optionsAccessor.Value.AllowValidatingTopLevelNodes &&
|
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
|
||||||
parameterInfo != null)
|
parameterInfo != null)
|
||||||
{
|
{
|
||||||
metadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
metadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
||||||
|
|
|
||||||
|
|
@ -1705,7 +1705,8 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
public async Task FromBody_JToken_ExcludedFromValidation()
|
public async Task FromBody_JToken_ExcludedFromValidation()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(new TestMvcOptions().Value);
|
var options = new TestMvcOptions().Value;
|
||||||
|
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(options);
|
||||||
var parameter = new ParameterDescriptor
|
var parameter = new ParameterDescriptor
|
||||||
{
|
{
|
||||||
Name = "Parameter1",
|
Name = "Parameter1",
|
||||||
|
|
@ -1718,11 +1719,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
};
|
};
|
||||||
|
|
||||||
var testContext = ModelBindingTestHelper.GetTestContext(
|
var testContext = ModelBindingTestHelper.GetTestContext(
|
||||||
request =>
|
updateRequest: request =>
|
||||||
{
|
{
|
||||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ message: \"Hello\" }"));
|
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ message: \"Hello\" }"));
|
||||||
request.ContentType = "application/json";
|
request.ContentType = "application/json";
|
||||||
});
|
},
|
||||||
|
mvcOptions: options);
|
||||||
|
|
||||||
var httpContext = testContext.HttpContext;
|
var httpContext = testContext.HttpContext;
|
||||||
var modelState = testContext.ModelState;
|
var modelState = testContext.ModelState;
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,11 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
|
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||||
|
|
||||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||||
defaultProvider.OnProvidersExecuting(context);
|
defaultProvider.OnProvidersExecuting(context);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -881,42 +881,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void CreateHandlerMethods_WithLegacyValidationBehavior_AddsParameterDescriptors()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var provider = new DefaultPageApplicationModelProvider(
|
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
|
||||||
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = false }),
|
|
||||||
Options.Create(new RazorPagesOptions()));
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PageWithHandlerParameters
|
private class PageWithHandlerParameters
|
||||||
{
|
{
|
||||||
public void OnPost(string name, [ModelBinder(Name = "personId")] int id) { }
|
public void OnPost(string name, [ModelBinder(Name = "personId")] int id) { }
|
||||||
|
|
@ -1078,8 +1042,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
// Arrange
|
// Arrange
|
||||||
var provider = new DefaultPageApplicationModelProvider(
|
var provider = new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new MvcOptions()),
|
|
||||||
Options.Create(new RazorPagesOptions()));
|
Options.Create(new RazorPagesOptions()));
|
||||||
|
|
||||||
var typeInfo = typeof(object).GetTypeInfo();
|
var typeInfo = typeof(object).GetTypeInfo();
|
||||||
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
|
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
|
||||||
|
|
||||||
|
|
@ -1225,7 +1189,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
return new DefaultPageApplicationModelProvider(
|
return new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
|
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
|
|
@ -145,10 +144,11 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
{
|
{
|
||||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new MvcOptions()),
|
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||||
|
|
||||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||||
defaultProvider.OnProvidersExecuting(context);
|
defaultProvider.OnProvidersExecuting(context);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
|
@ -461,10 +460,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
|
|
||||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
||||||
var mvcOptions = new MvcOptions
|
var mvcOptions = new MvcOptions();
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
var parameterBinder = new ParameterBinder(
|
var parameterBinder = new ParameterBinder(
|
||||||
modelMetadataProvider,
|
modelMetadataProvider,
|
||||||
|
|
|
||||||
|
|
@ -1544,15 +1544,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
var mvcOptions = new MvcOptions
|
var mvcOptions = new MvcOptions();
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new ParameterBinder(
|
return new ParameterBinder(
|
||||||
metadataProvider,
|
metadataProvider,
|
||||||
factory,
|
factory,
|
||||||
new DefaultObjectValidator(metadataProvider, new[] { validator }, new MvcOptions()),
|
new DefaultObjectValidator(metadataProvider, new[] { validator }, mvcOptions),
|
||||||
Options.Create(mvcOptions),
|
Options.Create(mvcOptions),
|
||||||
NullLoggerFactory.Instance);
|
NullLoggerFactory.Instance);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
public class PageBinderFactoryTest
|
public class PageBinderFactoryTest
|
||||||
{
|
{
|
||||||
private static readonly MvcOptions _options = new MvcOptions
|
private static readonly MvcOptions _options = new MvcOptions();
|
||||||
{
|
|
||||||
AllowValidatingTopLevelNodes = true,
|
|
||||||
};
|
|
||||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -712,56 +709,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task CreateHandlerBinder_DoesNotValidateTopLevelParameters_IfDisabled()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var type = typeof(PageModelWithExecutors);
|
|
||||||
var actionDescriptor = GetActionDescriptorWithHandlerMethod(
|
|
||||||
type,
|
|
||||||
nameof(PageModelWithExecutors.OnPostWithValidation));
|
|
||||||
|
|
||||||
// Act
|
|
||||||
|
|
||||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
|
||||||
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
|
||||||
var mvcOptions = new MvcOptions();
|
|
||||||
|
|
||||||
var parameterBinder = new ParameterBinder(
|
|
||||||
modelMetadataProvider,
|
|
||||||
modelBinderFactory,
|
|
||||||
new DefaultObjectValidator(
|
|
||||||
modelMetadataProvider,
|
|
||||||
new[] { TestModelValidatorProvider.CreateDefaultProvider() },
|
|
||||||
new MvcOptions()),
|
|
||||||
Options.Create(mvcOptions),
|
|
||||||
NullLoggerFactory.Instance);
|
|
||||||
|
|
||||||
var factory = PageBinderFactory.CreateHandlerBinder(
|
|
||||||
parameterBinder,
|
|
||||||
modelMetadataProvider,
|
|
||||||
modelBinderFactory,
|
|
||||||
actionDescriptor,
|
|
||||||
actionDescriptor.HandlerMethods[0],
|
|
||||||
mvcOptions);
|
|
||||||
|
|
||||||
var page = new PageWithProperty
|
|
||||||
{
|
|
||||||
PageContext = GetPageContext()
|
|
||||||
};
|
|
||||||
|
|
||||||
var model = new PageModelWithExecutors();
|
|
||||||
var arguments = new Dictionary<string, object>();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await factory(page.PageContext, arguments);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
var modelState = page.PageContext.ModelState;
|
|
||||||
Assert.True(modelState.IsValid);
|
|
||||||
Assert.Empty(modelState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CompiledPageActionDescriptor GetActionDescriptorWithHandlerMethod(Type type, string method)
|
private static CompiledPageActionDescriptor GetActionDescriptorWithHandlerMethod(Type type, string method)
|
||||||
{
|
{
|
||||||
var handlerMethodInfo = type.GetMethod(method);
|
var handlerMethodInfo = type.GetMethod(method);
|
||||||
|
|
@ -923,24 +870,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
public string PropertyWithNoValue { get; set; }
|
public string PropertyWithNoValue { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PageModelWithModelBinderAttribute
|
|
||||||
{
|
|
||||||
[ModelBinder(BinderType = typeof(DeclarativeSecurityAction))]
|
|
||||||
public Guid PropertyWithBinderType { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PageModelWithPropertyFilterAttribute
|
|
||||||
{
|
|
||||||
[ModelBinder]
|
|
||||||
[TestPropertyFilterProvider]
|
|
||||||
public object PropertyWithFilter { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TestPropertyFilterProvider : Attribute, IPropertyFilterProvider
|
|
||||||
{
|
|
||||||
public Func<ModelMetadata, bool> PropertyFilter => _ => true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PageModelWithDefaultValue
|
private class PageModelWithDefaultValue
|
||||||
{
|
{
|
||||||
[ModelBinder]
|
[ModelBinder]
|
||||||
|
|
|
||||||
|
|
@ -43,20 +43,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
||||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
|
||||||
Assert.True(mvcOptions.AllowBindingHeaderValuesToNonStringModelTypes);
|
|
||||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
|
||||||
Assert.True(razorPagesOptions.AllowAreas);
|
Assert.True(razorPagesOptions.AllowAreas);
|
||||||
Assert.True(mvcOptions.EnableEndpointRouting);
|
|
||||||
Assert.Equal(32, mvcOptions.MaxValidationDepth);
|
|
||||||
Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
|
|
||||||
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
|
|
||||||
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||||
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||||
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
||||||
Assert.False(apiBehaviorOptions.AllowInferringBindingSourceForCollectionTypesAsFromQuery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -81,20 +73,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
||||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
|
||||||
Assert.True(mvcOptions.AllowBindingHeaderValuesToNonStringModelTypes);
|
|
||||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
|
||||||
Assert.True(razorPagesOptions.AllowAreas);
|
Assert.True(razorPagesOptions.AllowAreas);
|
||||||
Assert.True(mvcOptions.EnableEndpointRouting);
|
|
||||||
Assert.Equal(32, mvcOptions.MaxValidationDepth);
|
|
||||||
Assert.False(apiBehaviorOptions.SuppressUseValidationProblemDetailsForInvalidModelStateResponses);
|
|
||||||
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
|
|
||||||
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||||
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||||
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
||||||
Assert.False(apiBehaviorOptions.AllowInferringBindingSourceForCollectionTypesAsFromQuery);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This just does the minimum needed to be able to resolve these options.
|
// This just does the minimum needed to be able to resolve these options.
|
||||||
|
|
|
||||||
|
|
@ -389,13 +389,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
typeof(RazorPagesOptionsConfigureCompatibilityOptions),
|
typeof(RazorPagesOptionsConfigureCompatibilityOptions),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
typeof(IPostConfigureOptions<MvcJsonOptions>),
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
typeof(MvcJsonOptionsConfigureCompatibilityOptions),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
typeof(IActionConstraintProvider),
|
typeof(IActionConstraintProvider),
|
||||||
new Type[]
|
new Type[]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace BasicWebSite
|
||||||
services.AddRouting();
|
services.AddRouting();
|
||||||
|
|
||||||
services.AddMvc()
|
services.AddMvc()
|
||||||
.SetCompatibilityVersion(CompatibilityVersion.Latest) // this compat version enables endpoint routing
|
.SetCompatibilityVersion(CompatibilityVersion.Latest)
|
||||||
.AddXmlDataContractSerializerFormatters();
|
.AddXmlDataContractSerializerFormatters();
|
||||||
|
|
||||||
services.ConfigureBaseWebSiteAuthPolicies();
|
services.ConfigureBaseWebSiteAuthPolicies();
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ namespace SecurityWebSite.Controllers
|
||||||
return Content("Administration.Index");
|
return Content("Administration.Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Either cookie should allow access to this action (if AllowCombiningAuthorizeFilters is true)
|
// Either cookie should allow access to this action.
|
||||||
// If AllowCombiningAuthorizeFilters is false, the main cookie is required.
|
|
||||||
[Authorize(AuthenticationSchemes = "Cookie2")]
|
[Authorize(AuthenticationSchemes = "Cookie2")]
|
||||||
public IActionResult EitherCookie()
|
public IActionResult EitherCookie()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue