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
|
||||
{
|
||||
private readonly MvcOptions _mvcOptions;
|
||||
private readonly IActionResultTypeMapper _mapper;
|
||||
private readonly ApiResponseTypeProvider _responseTypeProvider;
|
||||
private readonly RouteOptions _routeOptions;
|
||||
private readonly IInlineConstraintResolver _constraintResolver;
|
||||
|
|
@ -53,7 +52,8 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
/// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> used for resolving inline
|
||||
/// constraints.</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.")]
|
||||
public DefaultApiDescriptionProvider(
|
||||
IOptions<MvcOptions> optionsAccessor,
|
||||
|
|
@ -64,7 +64,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
_mvcOptions = optionsAccessor.Value;
|
||||
_constraintResolver = constraintResolver;
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_mapper = mapper;
|
||||
_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
|
||||
/// constraints.</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>
|
||||
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
|
||||
public DefaultApiDescriptionProvider(
|
||||
IOptions<MvcOptions> optionsAccessor,
|
||||
IInlineConstraintResolver constraintResolver,
|
||||
|
|
@ -87,7 +87,6 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
_mvcOptions = optionsAccessor.Value;
|
||||
_constraintResolver = constraintResolver;
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_mapper = mapper;
|
||||
_responseTypeProvider = new ApiResponseTypeProvider(modelMetadataProvider, mapper, _mvcOptions);
|
||||
_routeOptions = routeOptions.Value;
|
||||
}
|
||||
|
|
@ -202,8 +201,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
|||
var visitor = new PseudoModelBindingVisitor(context, actionParameter);
|
||||
|
||||
ModelMetadata metadata;
|
||||
if (_mvcOptions.AllowValidatingTopLevelNodes &&
|
||||
actionParameter is ControllerParameterDescriptor controllerParameterDescriptor &&
|
||||
if (actionParameter is ControllerParameterDescriptor controllerParameterDescriptor &&
|
||||
_modelMetadataProvider is ModelMetadataProvider provider)
|
||||
{
|
||||
// The default model metadata provider derives from ModelMetadataProvider
|
||||
|
|
|
|||
|
|
@ -15,29 +15,9 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public class ApiBehaviorOptions : IEnumerable<ICompatibilitySwitch>
|
||||
{
|
||||
private readonly CompatibilitySwitch<bool> _suppressMapClientErrors;
|
||||
private readonly CompatibilitySwitch<bool> _suppressUseValidationProblemDetailsForInvalidModelStateResponses;
|
||||
private readonly CompatibilitySwitch<bool> _allowInferringBindingSourceForCollectionTypesAsFromQuery;
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
|
||||
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
|
||||
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>
|
||||
/// Delegate invoked on actions annotated with <see cref="ApiControllerAttribute"/> to convert invalid
|
||||
/// <see cref="ModelStateDictionary"/> into an <see cref="IActionResult"/>
|
||||
|
|
@ -92,47 +72,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <value>
|
||||
/// The default value is <see langword="false"/>.
|
||||
/// </value>
|
||||
public bool SuppressMapClientErrors
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
public bool SuppressMapClientErrors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } =
|
||||
new Dictionary<int, ClientErrorData>();
|
||||
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } = new Dictionary<int, ClientErrorData>();
|
||||
|
||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,12 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
if (!options.SuppressInferBindingSourcesForParameters)
|
||||
{
|
||||
var convention = new InferParameterBindingInfoConvention(modelMetadataProvider)
|
||||
{
|
||||
AllowInferringBindingSourceForCollectionTypesAsFromQuery = options.AllowInferringBindingSourceForCollectionTypesAsFromQuery,
|
||||
};
|
||||
|
||||
ActionModelConventions.Add(convention);
|
||||
ActionModelConventions.Add(new InferParameterBindingInfoConvention(modelMetadataProvider));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -454,7 +454,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
var attributes = parameterInfo.GetCustomAttributes(inherit: true);
|
||||
|
||||
BindingInfo bindingInfo;
|
||||
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
{
|
||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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">
|
||||
/// <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>
|
||||
|
|
@ -31,8 +31,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
_modelMetadataProvider = modelMetadataProvider ?? throw new ArgumentNullException(nameof(modelMetadataProvider));
|
||||
}
|
||||
|
||||
internal bool AllowInferringBindingSourceForCollectionTypesAsFromQuery { get; set; }
|
||||
|
||||
protected virtual bool ShouldApply(ActionModel action) => true;
|
||||
|
||||
public void Apply(ActionModel action)
|
||||
|
|
@ -118,13 +116,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
private bool IsComplexTypeParameter(ParameterModel parameter)
|
||||
{
|
||||
// No need for information from attributes on the parameter. Just use its type.
|
||||
var metadata = _modelMetadataProvider
|
||||
.GetMetadataForType(parameter.ParameterInfo.ParameterType);
|
||||
|
||||
if (AllowInferringBindingSourceForCollectionTypesAsFromQuery && metadata.IsCollectionType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var metadata = _modelMetadataProvider.GetMetadataForType(parameter.ParameterInfo.ParameterType);
|
||||
|
||||
return metadata.IsComplexType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
|||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Authorization
|
||||
{
|
||||
|
|
@ -23,7 +22,6 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
/// </summary>
|
||||
public class AuthorizeFilter : IAsyncAuthorizationFilter, IFilterFactory
|
||||
{
|
||||
private MvcOptions _mvcOptions;
|
||||
private AuthorizationPolicy _effectivePolicy;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -136,38 +134,25 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
var effectivePolicy = await ComputePolicyAsync();
|
||||
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 (_mvcOptions.AllowCombiningAuthorizeFilters)
|
||||
{
|
||||
if (!context.IsEffectivePolicy(this))
|
||||
if (ReferenceEquals(this, context.Filters[i]))
|
||||
{
|
||||
return null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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++)
|
||||
if (context.Filters[i] is AuthorizeFilter authorizeFilter)
|
||||
{
|
||||
if (ReferenceEquals(this, context.Filters[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// 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
|
||||
if (canCache)
|
||||
{
|
||||
|
|
@ -185,6 +170,11 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (!context.IsEffectivePolicy(this))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var effectivePolicy = await GetEffectivePolicyAsync(context);
|
||||
if (effectivePolicy == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,8 +54,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <remarks>
|
||||
/// ASP.NET Core MVC 2.1 introduced compatibility switches for the following:
|
||||
/// <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.SuppressBindingUndefinedValueToEnumType"/></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:
|
||||
/// <list type="bullet">
|
||||
/// <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><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
|
||||
/// <item><description><see cref="MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent"/></description></item>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Controllers
|
||||
|
|
@ -134,8 +133,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
|||
var parameter = parameters[i];
|
||||
|
||||
ModelMetadata metadata;
|
||||
if (mvcOptions.AllowValidatingTopLevelNodes &&
|
||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||
parameter is ControllerParameterDescriptor controllerParameterDescriptor)
|
||||
{
|
||||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
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> ProblemDetailsFactory = ProblemDetailsInvalidModelStateResponse;
|
||||
|
||||
public ApiBehaviorOptionsSetup(
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<MvcCompatibilityOptions> compatibilityOptions)
|
||||
: base(loggerFactory, compatibilityOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IReadOnlyDictionary<string, object> DefaultValues
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
}
|
||||
internal static readonly Func<ActionContext, IActionResult> ProblemDetailsFactory =
|
||||
ProblemDetailsInvalidModelStateResponse;
|
||||
|
||||
public void Configure(ApiBehaviorOptions options)
|
||||
{
|
||||
|
|
@ -45,11 +29,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
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
|
||||
// (a) it has not been opted out of (SuppressMapClientErrors = true)
|
||||
// (b) a different factory was configured
|
||||
|
|
|
|||
|
|
@ -30,18 +30,18 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
/// <summary>
|
||||
/// Adds the minimum essential MVC services to the specified <see cref="IServiceCollection" />. Additional services
|
||||
/// including MVC's support for authorization, formatters, and validation must be added separately using the
|
||||
/// including MVC's support for authorization, formatters, and validation must be added separately using the
|
||||
/// <see cref="IMvcCoreBuilder"/> returned from this method.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <returns>An <see cref="IMvcCoreBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// The <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/> approach for configuring
|
||||
/// MVC is provided for experienced MVC developers who wish to have full control over the set of default services
|
||||
/// MVC is provided for experienced MVC developers who wish to have full control over the set of default services
|
||||
/// registered. <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/> will register
|
||||
/// the minimum set of services necessary to route requests and invoke controllers. It is not expected that any
|
||||
/// the minimum set of services necessary to route requests and invoke controllers. It is not expected that any
|
||||
/// application will satisfy its requirements with just a call to
|
||||
/// <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>. Additional configuration using the
|
||||
/// <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>. Additional configuration using the
|
||||
/// <see cref="IMvcCoreBuilder"/> will be required.
|
||||
/// </remarks>
|
||||
public static IMvcCoreBuilder AddMvcCore(this IServiceCollection services)
|
||||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
|
||||
/// <summary>
|
||||
/// Adds the minimum essential MVC services to the specified <see cref="IServiceCollection" />. Additional services
|
||||
/// including MVC's support for authorization, formatters, and validation must be added separately using the
|
||||
/// including MVC's support for authorization, formatters, and validation must be added separately using the
|
||||
/// <see cref="IMvcCoreBuilder"/> returned from this method.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
|
|
@ -108,11 +108,11 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// <returns>An <see cref="IMvcCoreBuilder"/> that can be used to further configure the MVC services.</returns>
|
||||
/// <remarks>
|
||||
/// The <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/> approach for configuring
|
||||
/// MVC is provided for experienced MVC developers who wish to have full control over the set of default services
|
||||
/// MVC is provided for experienced MVC developers who wish to have full control over the set of default services
|
||||
/// registered. <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/> will register
|
||||
/// the minimum set of services necessary to route requests and invoke controllers. It is not expected that any
|
||||
/// the minimum set of services necessary to route requests and invoke controllers. It is not expected that any
|
||||
/// application will satisfy its requirements with just a call to
|
||||
/// <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>. Additional configuration using the
|
||||
/// <see cref="MvcCoreServiceCollectionExtensions.AddMvcCore(IServiceCollection)"/>. Additional configuration using the
|
||||
/// <see cref="IMvcCoreBuilder"/> will be required.
|
||||
/// </remarks>
|
||||
public static IMvcCoreBuilder AddMvcCore(
|
||||
|
|
|
|||
|
|
@ -49,20 +49,22 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
|
||||
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor)
|
||||
{
|
||||
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);
|
||||
var controllerContext = new ControllerContext(context.ActionContext)
|
||||
{
|
||||
// PERF: These are rarely going to be changed, so let's go copy-on-write.
|
||||
ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories)
|
||||
};
|
||||
controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors;
|
||||
|
||||
var cacheResult = _controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
|
||||
var invoker = new ControllerActionInvoker(
|
||||
_logger,
|
||||
_diagnosticListener,
|
||||
_mapper,
|
||||
controllerContext,
|
||||
cacheResult.cacheEntry,
|
||||
cacheResult.filters);
|
||||
cacheEntry,
|
||||
filters);
|
||||
|
||||
context.Result = invoker;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
{
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
[nameof(MvcOptions.AllowCombiningAuthorizeFilters)] = true,
|
||||
[nameof(MvcOptions.AllowBindingHeaderValuesToNonStringModelTypes)] = true,
|
||||
[nameof(MvcOptions.AllowValidatingTopLevelNodes)] = true,
|
||||
[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions,
|
||||
[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true,
|
||||
[nameof(MvcOptions.EnableEndpointRouting)] = true,
|
||||
|
||||
// Matches JsonSerializerSettingsProvider.DefaultMaxDepth
|
||||
[nameof(MvcOptions.MaxValidationDepth)] = 32,
|
||||
|
||||
[nameof(MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent)] = true,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
/// The <see cref="IModelBinder"/> for binding <typeparamref name="TElement"/>.
|
||||
/// </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)
|
||||
: 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
|
||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||
/// </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(
|
||||
IModelBinder elementBinder,
|
||||
ILoggerFactory loggerFactory,
|
||||
bool allowValidatingTopLevelNodes)
|
||||
: base(elementBinder, loggerFactory, allowValidatingTopLevelNodes)
|
||||
: base(elementBinder, loggerFactory, allowValidatingTopLevelNodes: true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||
{
|
||||
|
|
@ -28,12 +27,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
var binderType = typeof(ArrayModelBinder<>).MakeGenericType(elementType);
|
||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
return (IModelBinder)Activator.CreateInstance(
|
||||
binderType,
|
||||
elementBinder,
|
||||
loggerFactory,
|
||||
mvcOptions.AllowValidatingTopLevelNodes);
|
||||
true /* allowValidatingTopLevelNodes */);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -42,12 +42,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
/// </summary>
|
||||
/// <param name="elementBinder">The <see cref="IModelBinder"/> for binding elements.</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)
|
||||
: this(elementBinder, loggerFactory, allowValidatingTopLevelNodes: false)
|
||||
: this(elementBinder, loggerFactory, allowValidatingTopLevelNodes: true)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -196,16 +192,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
/// </summary>
|
||||
/// <param name="bindingContext">The <see cref="ModelBindingContext"/>.</param>
|
||||
/// <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
|
||||
/// <see cref="ModelBindingResult.IsModelSet" /> equal to <see langword="true" /> when a
|
||||
/// top-level model is not bound. Therefore, ParameterBinder can not detect a
|
||||
/// <see cref="ModelMetadata.IsBindingRequired" /> failure for collections. Add the error here.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected void AddErrorIfBindingRequired(ModelBindingContext bindingContext)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
binderType,
|
||||
elementBinder,
|
||||
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
|
||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
binderType,
|
||||
elementBinder,
|
||||
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.
|
||||
/// </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(
|
||||
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
||||
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
|
||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||
/// </param>
|
||||
/// <remarks>The <paramref name="allowValidatingTopLevelNodes"/> parameter is currently ignored.</remarks>
|
||||
public ComplexTypeModelBinder(
|
||||
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
|
||||
ILoggerFactory loggerFactory,
|
||||
|
|
@ -84,13 +81,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
_propertyBinders = propertyBinders;
|
||||
_logger = loggerFactory.CreateLogger<ComplexTypeModelBinder>();
|
||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal bool AllowValidatingTopLevelNodes { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task BindModelAsync(ModelBindingContext bindingContext)
|
||||
{
|
||||
if (bindingContext == null)
|
||||
|
|
@ -172,8 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
// 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.
|
||||
// 3. No data exists for any property.
|
||||
if (AllowValidatingTopLevelNodes &&
|
||||
!attemptedPropertyBinding &&
|
||||
if (!attemptedPropertyBinding &&
|
||||
bindingContext.IsTopLevelObject &&
|
||||
modelMetadata.IsBindingRequired)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||
{
|
||||
|
|
@ -32,11 +31,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
}
|
||||
|
||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||
var mvcOptions = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
return new ComplexTypeModelBinder(
|
||||
propertyBinders,
|
||||
loggerFactory,
|
||||
mvcOptions.AllowValidatingTopLevelNodes);
|
||||
allowValidatingTopLevelNodes: true);
|
||||
}
|
||||
|
||||
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="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</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)
|
||||
: 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
|
||||
/// adds a <see cref="ModelStateDictionary"/> error when the model is not bound.
|
||||
/// </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(
|
||||
IModelBinder keyBinder,
|
||||
IModelBinder valueBinder,
|
||||
|
|
@ -84,12 +87,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
}
|
||||
|
||||
_valueBinder = valueBinder;
|
||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal new bool AllowValidatingTopLevelNodes { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
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
|
||||
// replaced the ValueProvider with something other than a CompositeValueProvider.
|
||||
if (AllowValidatingTopLevelNodes && bindingContext.IsTopLevelObject)
|
||||
if (bindingContext.IsTopLevelObject)
|
||||
{
|
||||
AddErrorIfBindingRequired(bindingContext);
|
||||
}
|
||||
|
|
@ -135,7 +134,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
if (keys.Count == 0)
|
||||
{
|
||||
// No entries with the expected keys.
|
||||
if (AllowValidatingTopLevelNodes && bindingContext.IsTopLevelObject)
|
||||
if (bindingContext.IsTopLevelObject)
|
||||
{
|
||||
AddErrorIfBindingRequired(bindingContext);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
keyBinder,
|
||||
valueBinder,
|
||||
loggerFactory,
|
||||
mvcOptions.AllowValidatingTopLevelNodes);
|
||||
true /* allowValidatingTopLevelNodes */);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||
{
|
||||
|
|
@ -32,23 +31,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||
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))
|
||||
{
|
||||
logger.CannotCreateHeaderModelBinder(modelMetadata.ModelType);
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
|
|||
|
||||
if (defaultModelMetadata.ValidationMetadata.HasValidators != false)
|
||||
{
|
||||
// Either the ModelMetadata instance has some validators (HasValidators = true) or it is non-deterministic (HasValidators = null).
|
||||
// Either the ModelMetadata instance has some validators (HasValidators = true) or it is non-deterministic (HasValidators = null).
|
||||
// In either case, assume it has validators.
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
private readonly IModelBinderFactory _modelBinderFactory;
|
||||
private readonly MvcOptions _mvcOptions;
|
||||
private readonly IObjectModelValidator _objectModelValidator;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -55,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
|
||||
/// <param name="mvcOptions">The <see cref="MvcOptions"/> accessor.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
/// <remarks>The <paramref name="mvcOptions"/> parameter is currently unused.</remarks>
|
||||
public ParameterBinder(
|
||||
IModelMetadataProvider modelMetadataProvider,
|
||||
IModelBinderFactory modelBinderFactory,
|
||||
|
|
@ -90,7 +90,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_modelBinderFactory = modelBinderFactory;
|
||||
_objectModelValidator = validator;
|
||||
_mvcOptions = mvcOptions.Value;
|
||||
Logger = loggerFactory.CreateLogger(GetType());
|
||||
}
|
||||
|
||||
|
|
@ -260,8 +259,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
|
||||
var modelBindingResult = modelBindingContext.Result;
|
||||
|
||||
if (_mvcOptions.AllowValidatingTopLevelNodes &&
|
||||
_objectModelValidator is ObjectModelValidator baseObjectValidator)
|
||||
if (_objectModelValidator is ObjectModelValidator baseObjectValidator)
|
||||
{
|
||||
Logger.AttemptingToValidateParameterOrProperty(parameter, metadata);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,10 +39,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
|||
validatorProvider,
|
||||
validatorCache,
|
||||
metadataProvider,
|
||||
validationState);
|
||||
|
||||
visitor.MaxValidationDepth = _mvcOptions.MaxValidationDepth;
|
||||
visitor.AllowShortCircuitingValidationWhenNoValidatorsArePresent = _mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent;
|
||||
validationState)
|
||||
{
|
||||
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
|
||||
AllowShortCircuitingValidationWhenNoValidatorsArePresent =
|
||||
_mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent,
|
||||
};
|
||||
|
||||
return visitor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,11 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
|
||||
|
|
@ -22,18 +19,14 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
|
||||
{
|
||||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||
|
||||
// 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<bool> _suppressBindingUndefinedValueToEnumType;
|
||||
private readonly CompatibilitySwitch<bool> _enableEndpointRouting;
|
||||
private readonly NullableCompatibilitySwitch<int> _maxValidationDepth;
|
||||
private readonly CompatibilitySwitch<bool> _allowShortCircuitingValidationWhenNoValidatorsArePresent;
|
||||
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||
private int? _maxValidationDepth = 32;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="MvcOptions"/>.
|
||||
|
|
@ -52,24 +45,14 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||
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);
|
||||
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
||||
_enableEndpointRouting = new CompatibilitySwitch<bool>(nameof(EnableEndpointRouting));
|
||||
_maxValidationDepth = new NullableCompatibilitySwitch<int>(nameof(MaxValidationDepth));
|
||||
_allowShortCircuitingValidationWhenNoValidatorsArePresent = new CompatibilitySwitch<bool>(nameof(AllowShortCircuitingValidationWhenNoValidatorsArePresent));
|
||||
|
||||
_switches = new ICompatibilitySwitch[]
|
||||
{
|
||||
_allowCombiningAuthorizeFilters,
|
||||
_allowBindingHeaderValuesToNonStringModelTypes,
|
||||
_allowValidatingTopLevelNodes,
|
||||
_inputFormatterExceptionPolicy,
|
||||
_suppressBindingUndefinedValueToEnumType,
|
||||
_enableEndpointRouting,
|
||||
_maxValidationDepth,
|
||||
_allowShortCircuitingValidationWhenNoValidatorsArePresent,
|
||||
};
|
||||
}
|
||||
|
|
@ -82,11 +65,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// <value>
|
||||
/// The default value is <see langword="true"/>.
|
||||
/// </value>
|
||||
public bool EnableEndpointRouting
|
||||
{
|
||||
get => _enableEndpointRouting.Value;
|
||||
set => _enableEndpointRouting.Value = value;
|
||||
}
|
||||
public bool EnableEndpointRouting { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flag which decides whether body model binding (for example, on an
|
||||
|
|
@ -100,58 +79,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </example>
|
||||
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>
|
||||
/// Gets a Dictionary of CacheProfile Names, <see cref="CacheProfile"/> which are pre-defined settings for
|
||||
/// response caching.
|
||||
|
|
@ -311,7 +238,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </value>
|
||||
public int? MaxValidationDepth
|
||||
{
|
||||
get => _maxValidationDepth.Value;
|
||||
get => _maxValidationDepth;
|
||||
set
|
||||
{
|
||||
if (value != null && value <= 0)
|
||||
|
|
@ -319,7 +246,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
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",
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcJsonOptions>, MvcJsonOptionsConfigureCompatibilityOptions>());
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IApiDescriptionProvider, JsonPatchOperationsArrayProvider>());
|
||||
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.
|
||||
// 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.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
|
|
@ -15,21 +16,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
|
||||
{
|
||||
private readonly CompatibilitySwitch<bool> _allowInputFormatterExceptionMessages;
|
||||
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,
|
||||
};
|
||||
}
|
||||
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// detailed error messages about submitted JSON data.
|
||||
/// </remarks>
|
||||
public bool AllowInputFormatterExceptionMessages
|
||||
{
|
||||
get => _allowInputFormatterExceptionMessages.Value;
|
||||
set => _allowInputFormatterExceptionMessages.Value = value;
|
||||
}
|
||||
public bool AllowInputFormatterExceptionMessages { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="JsonSerializerSettings"/> that are used by this application.
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
/// <summary>
|
||||
/// Serializes <see cref="IEnumerable{T}"/> types by delegating them through a concrete implementation.
|
||||
/// </summary>
|
||||
/// <typeparam name="TWrapped">The wrapping or original type of the <see cref="IEnumerable{T}"/>
|
||||
/// <typeparam name="TWrapped">The wrapping or original type of the <see cref="IEnumerable{T}"/>
|
||||
/// to proxy.</typeparam>
|
||||
/// <typeparam name="TDeclared">The type parameter of the original <see cref="IEnumerable{T}"/>
|
||||
/// <typeparam name="TDeclared">The type parameter of the original <see cref="IEnumerable{T}"/>
|
||||
/// to proxy.</typeparam>
|
||||
public class DelegatingEnumerable<TWrapped, TDeclared> : IEnumerable<TWrapped>
|
||||
{
|
||||
|
|
@ -21,10 +21,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
private readonly IWrapperProvider _wrapperProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="DelegatingEnumerable{TWrapped, TDeclared}"/>.
|
||||
/// Initializes a <see cref="DelegatingEnumerable{TWrapped, TDeclared}"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This constructor is necessary for <see cref="System.Runtime.Serialization.DataContractSerializer"/>
|
||||
/// This constructor is necessary for <see cref="System.Runtime.Serialization.DataContractSerializer"/>
|
||||
/// to serialize.
|
||||
/// </remarks>
|
||||
public DelegatingEnumerable()
|
||||
|
|
@ -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
|
||||
/// method so that the type can be serialized. This will never be called.
|
||||
/// </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)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
|
@ -80,4 +81,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
private readonly PageHandlerPageFilter _pageHandlerPageFilter = new PageHandlerPageFilter();
|
||||
private readonly PageHandlerResultFilter _pageHandlerResultFilter = new PageHandlerResultFilter();
|
||||
private readonly IModelMetadataProvider _modelMetadataProvider;
|
||||
private readonly MvcOptions _mvcOptions;
|
||||
private readonly RazorPagesOptions _razorPagesOptions;
|
||||
private readonly Func<ActionContext, bool> _supportsAllRequests;
|
||||
private readonly Func<ActionContext, bool> _supportsNonGetRequests;
|
||||
|
|
@ -29,11 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
|
||||
public DefaultPageApplicationModelProvider(
|
||||
IModelMetadataProvider modelMetadataProvider,
|
||||
IOptions<MvcOptions> options,
|
||||
IOptions<RazorPagesOptions> razorPagesOptions)
|
||||
{
|
||||
_modelMetadataProvider = modelMetadataProvider;
|
||||
_mvcOptions = options.Value;
|
||||
_razorPagesOptions = razorPagesOptions.Value;
|
||||
|
||||
_supportsAllRequests = _ => true;
|
||||
|
|
@ -248,7 +245,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
var attributes = parameter.GetCustomAttributes(inherit: true);
|
||||
|
||||
BindingInfo bindingInfo;
|
||||
if (_mvcOptions.AllowValidatingTopLevelNodes && _modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
if (_modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
{
|
||||
var modelMetadata = modelMetadataProviderBase.GetMetadataForParameter(parameter);
|
||||
bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);
|
||||
|
|
|
|||
|
|
@ -102,8 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
{
|
||||
var parameter = handler.Parameters[i];
|
||||
ModelMetadata metadata;
|
||||
if (mvcOptions.AllowValidatingTopLevelNodes &&
|
||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase)
|
||||
{
|
||||
// The default model metadata provider derives from ModelMetadataProvider
|
||||
// and can therefore supply information about attributes applied to parameters.
|
||||
|
|
|
|||
|
|
@ -1180,25 +1180,6 @@ namespace Microsoft.AspNetCore.Mvc.Description
|
|||
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]
|
||||
public void GetApiDescription_ParameterDescription_SourceFromRouteData()
|
||||
{
|
||||
|
|
@ -1816,15 +1797,11 @@ namespace Microsoft.AspNetCore.Mvc.Description
|
|||
ActionDescriptor action,
|
||||
List<MockInputFormatter> inputFormatters = null,
|
||||
List<MockOutputFormatter> outputFormatters = null,
|
||||
bool allowValidatingTopLevelNodes = true,
|
||||
RouteOptions routeOptions = null)
|
||||
{
|
||||
var context = new ApiDescriptionProviderContext(new ActionDescriptor[] { action });
|
||||
|
||||
var options = new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes,
|
||||
};
|
||||
var options = new MvcOptions();
|
||||
foreach (var formatter in inputFormatters ?? CreateInputFormatters())
|
||||
{
|
||||
options.InputFormatters.Add(formatter);
|
||||
|
|
|
|||
|
|
@ -169,19 +169,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
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
|
||||
{
|
||||
public IActionResult TestAction(object value) => null;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
IModelMetadataProvider modelMetadataProvider = null)
|
||||
{
|
||||
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();
|
||||
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
||||
convention.OnProvidersExecuting(context);
|
||||
|
|
@ -68,12 +68,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
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)
|
||||
{
|
||||
var context = GetContext(controllerType);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
{
|
||||
// Arrange
|
||||
var builder = new TestApplicationModelProvider(
|
||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
||||
new MvcOptions(),
|
||||
TestModelMetadataProvider.CreateDefaultProvider());
|
||||
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
{
|
||||
// Arrange
|
||||
var builder = new TestApplicationModelProvider(
|
||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
||||
new MvcOptions(),
|
||||
TestModelMetadataProvider.CreateDefaultProvider());
|
||||
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]
|
||||
public void OnProvidersExecuting_InfersFormFileSourceForTypesAssignableFromIEnumerableOfFormFiles()
|
||||
{
|
||||
// Arrange
|
||||
var builder = new TestApplicationModelProvider(
|
||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
||||
new MvcOptions(),
|
||||
TestModelMetadataProvider.CreateDefaultProvider());
|
||||
var typeInfo = typeof(ModelBinderController).GetTypeInfo();
|
||||
|
||||
|
|
@ -286,7 +241,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
public void OnProvidersExecuting_AddsBindingSources_ForActionParameters_ReadFromModelMetadata()
|
||||
{
|
||||
// Arrange
|
||||
var options = new MvcOptions { AllowValidatingTopLevelNodes = true };
|
||||
var options = new MvcOptions();
|
||||
var detailsProvider = new BindingSourceMetadataProvider(typeof(Guid), BindingSource.Special);
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(new[] { detailsProvider });
|
||||
|
||||
|
|
@ -1822,9 +1777,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
private class TestApplicationModelProvider : DefaultApplicationModelProvider
|
||||
{
|
||||
public TestApplicationModelProvider()
|
||||
: this(
|
||||
new MvcOptions { AllowValidatingTopLevelNodes = true },
|
||||
new EmptyModelMetadataProvider())
|
||||
: this(new MvcOptions(), new EmptyModelMetadataProvider())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1836,4 +1789,4 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -468,22 +468,6 @@ Environment.NewLine + "int b";
|
|||
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]
|
||||
public void InferBindingSourceForParameter_ReturnsBodyForCollectionOfComplexTypes()
|
||||
{
|
||||
|
|
@ -499,22 +483,6 @@ Environment.NewLine + "int b";
|
|||
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]
|
||||
public void PreservesBindingSourceInference_ForFromQueryParameter_WithDefaultName()
|
||||
{
|
||||
|
|
@ -782,7 +750,7 @@ Environment.NewLine + "int b";
|
|||
IModelMetadataProvider modelMetadataProvider = null)
|
||||
{
|
||||
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();
|
||||
var convention = new DefaultApplicationModelProvider(mvcOptions, modelMetadataProvider);
|
||||
convention.OnProvidersExecuting(context);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
||||
|
||||
// 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
|
||||
// this filter.
|
||||
|
|
@ -38,6 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
var filterFactory = authorizeFilterFactory as IFilterFactory;
|
||||
var authorizeFilter = (AuthorizeFilter)filterFactory.CreateInstance(
|
||||
authorizationContext.HttpContext.RequestServices);
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
|
||||
// Act
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||
|
|
@ -52,6 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
||||
var authorizationContext = GetAuthorizationContext();
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
||||
"IAuthorizationPolicyProvider.";
|
||||
|
||||
|
|
@ -67,6 +70,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new[] { new AuthorizeAttribute() });
|
||||
var authorizationContext = GetAuthorizationContext();
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var expected = "An AuthorizationPolicy cannot be created without a valid instance of " +
|
||||
"IAuthorizationPolicyProvider.";
|
||||
|
||||
|
|
@ -101,6 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
.Callback(() => getPolicyCount++);
|
||||
var authorizeFilter = new AuthorizeFilter(policyProvider.Object, new AuthorizeAttribute[] { new AuthorizeAttribute("whatever") });
|
||||
var authorizationContext = GetAuthorizationContext();
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
|
||||
// Act & Assert
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||
|
|
@ -153,6 +158,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: true);
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
|
||||
// Act
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||
|
|
@ -223,8 +229,10 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
|
||||
private class TestPolicyProvider : IAuthorizationPolicyProvider
|
||||
{
|
||||
private AuthorizationPolicy _true = new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
|
||||
private AuthorizationPolicy _false = new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build();
|
||||
private readonly AuthorizationPolicy _true =
|
||||
new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
|
||||
private readonly AuthorizationPolicy _false =
|
||||
new AuthorizationPolicyBuilder().RequireAssertion(_ => false).Build();
|
||||
|
||||
public int GetPolicyCalls = 0;
|
||||
|
||||
|
|
@ -250,7 +258,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
new AuthorizeAttribute { Policy = "true"},
|
||||
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
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||
|
|
@ -269,12 +277,12 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Arrange
|
||||
var testProvider1 = new TestPolicyProvider();
|
||||
var testProvider2 = new TestPolicyProvider();
|
||||
var authorizeFilter = new AuthorizeFilter(testProvider1, new IAuthorizeData[]
|
||||
var authorizeFilter = new AuthorizeFilter(testProvider1, new IAuthorizeData[]
|
||||
{
|
||||
new AuthorizeAttribute { Policy = "true"},
|
||||
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
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||
|
|
@ -304,7 +312,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
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
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||
|
|
@ -322,7 +330,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
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
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||
|
|
@ -340,7 +348,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
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
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
authorizationContext.Filters.Add(new DerivedAuthorizeFilter());
|
||||
|
|
@ -354,8 +362,8 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Assert
|
||||
Assert.IsType<ForbidResult>(authorizationContext.Result);
|
||||
}
|
||||
|
||||
public class DerivedAuthorizeFilter : AuthorizeFilter
|
||||
|
||||
public class DerivedAuthorizeFilter : AuthorizeFilter
|
||||
{
|
||||
public DerivedAuthorizeFilter() : base(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build())
|
||||
{ }
|
||||
|
|
@ -381,6 +389,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireRole("Wut").Build());
|
||||
var authorizationContext = GetAuthorizationContext();
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
|
||||
// Act
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||
|
|
@ -397,6 +406,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
.RequireClaim("Permission", "CanViewComment")
|
||||
.Build());
|
||||
var authorizationContext = GetAuthorizationContext();
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
|
||||
// Act
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationContext);
|
||||
|
|
@ -532,10 +542,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
serviceCollection.AddSingleton(auth.Object);
|
||||
serviceCollection.AddAuthorization();
|
||||
serviceCollection.AddAuthorizationPolicyEvaluator();
|
||||
if (registerServices != null)
|
||||
{
|
||||
registerServices(serviceCollection);
|
||||
}
|
||||
registerServices?.Invoke(serviceCollection);
|
||||
|
||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
@ -557,7 +564,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
routeData: new RouteData(),
|
||||
actionDescriptor: new ActionDescriptor());
|
||||
|
||||
var authorizationContext = new Filters.AuthorizationFilterContext(
|
||||
var authorizationContext = new AuthorizationFilterContext(
|
||||
actionContext,
|
||||
Enumerable.Empty<IFilterMetadata>().ToList()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.Reflection;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
|
@ -28,10 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
|||
{
|
||||
public class ControllerBinderDelegateProviderTest
|
||||
{
|
||||
private static readonly MvcOptions _options = new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
};
|
||||
private static readonly MvcOptions _options = new MvcOptions();
|
||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
||||
|
||||
[Fact]
|
||||
|
|
@ -428,55 +424,6 @@ namespace Microsoft.AspNetCore.Mvc.Controllers
|
|||
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]
|
||||
public async Task CreateBinderDelegate_Delegate_DoesNotCallValidator_IfModelBinderFails()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
|
|
@ -18,9 +16,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
public void Configure_AssignsInvalidModelStateResponseFactory()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
||||
NullLoggerFactory.Instance,
|
||||
Options.Options.Create(new MvcCompatibilityOptions()));
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||
var options = new ApiBehaviorOptions();
|
||||
|
||||
// Act
|
||||
|
|
@ -35,9 +31,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
// Arrange
|
||||
var expected = new[] { 400, 401, 403, 404, 406, 409, 415, 422, };
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
||||
NullLoggerFactory.Instance,
|
||||
Options.Options.Create(new MvcCompatibilityOptions()));
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||
var options = new ApiBehaviorOptions();
|
||||
|
||||
// Act
|
||||
|
|
@ -51,9 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
public void PostConfigure_SetProblemDetailsModelStateResponseFactory()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
||||
NullLoggerFactory.Instance,
|
||||
Options.Options.Create(new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Latest }));
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||
var options = new ApiBehaviorOptions();
|
||||
|
||||
// Act
|
||||
|
|
@ -68,9 +60,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
public void PostConfigure_DoesNotSetProblemDetailsFactory_IfValueWasModified()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup(
|
||||
NullLoggerFactory.Instance,
|
||||
Options.Options.Create(new MvcCompatibilityOptions { CompatibilityVersion = CompatibilityVersion.Latest }));
|
||||
var optionsSetup = new ApiBehaviorOptionsSetup();
|
||||
var options = new ApiBehaviorOptions();
|
||||
Func<ActionContext, IActionResult> expected = _ => null;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
new[] { new DefaultFilterProvider() });
|
||||
|
||||
// Act
|
||||
var cacheEntry1 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var cacheEntry2 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var (cacheEntry, filters) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var (cacheEntry2, filters2) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(cacheEntry1.filters, cacheEntry2.filters);
|
||||
Assert.Equal(filters, filters2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -54,11 +54,11 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
new[] { new DefaultFilterProvider() });
|
||||
|
||||
// Act
|
||||
var cacheEntry1 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var cacheEntry2 = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var (cacheEntry, filters) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
var (cacheEntry2, filters2) = controllerActionInvokerCache.GetCachedResult(controllerContext);
|
||||
|
||||
// Assert
|
||||
Assert.Same(cacheEntry1.cacheEntry, cacheEntry2.cacheEntry);
|
||||
Assert.Same(cacheEntry, cacheEntry2);
|
||||
}
|
||||
|
||||
private class TestFilter : IFilterMetadata
|
||||
|
|
@ -100,10 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
new[] { controllerContext.ActionDescriptor });
|
||||
var modelMetadataProvider = new EmptyModelMetadataProvider();
|
||||
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
||||
var mvcOptions = Options.Create(new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
});
|
||||
var mvcOptions = Options.Create(new MvcOptions());
|
||||
|
||||
return new ControllerActionInvokerCache(
|
||||
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);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void Create_ForArrayType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
||||
bool allowValidatingTopLevelNodes)
|
||||
[Fact]
|
||||
public void Create_ForArrayType_ReturnsBinder()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new ArrayModelBinderProvider();
|
||||
|
||||
var context = new TestModelBinderProviderContext(typeof(int[]));
|
||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
||||
context.OnCreatingBinder(m =>
|
||||
{
|
||||
Assert.Equal(typeof(int), m.ModelType);
|
||||
|
|
@ -73,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
// Assert
|
||||
var binder = Assert.IsType<ArrayModelBinder<int>>(result);
|
||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
||||
Assert.True(binder.AllowValidatingTopLevelNodes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -48,11 +48,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
[InlineData(false, false)]
|
||||
[InlineData(false, true)]
|
||||
[InlineData(true, false)]
|
||||
[InlineData(true, true)]
|
||||
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
||||
bool allowValidatingTopLevelNodes,
|
||||
bool isBindingRequired)
|
||||
{
|
||||
// Arrange
|
||||
var expectedErrorCount = isBindingRequired ? 1 : 0;
|
||||
var binder = new ArrayModelBinder<string>(
|
||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||
NullLoggerFactory.Instance,
|
||||
|
|
@ -81,7 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
// Assert
|
||||
Assert.Empty(Assert.IsType<string[]>(bindingContext.Result.Model));
|
||||
Assert.True(bindingContext.Result.IsModelSet);
|
||||
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
||||
Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void Create_ForSupportedType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
||||
bool allowValidatingTopLevelNodes)
|
||||
[Fact]
|
||||
public void Create_ForSupportedType_ReturnsBinder()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new CollectionModelBinderProvider();
|
||||
|
||||
var context = new TestModelBinderProviderContext(typeof(List<int>));
|
||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
||||
context.OnCreatingBinder(m =>
|
||||
{
|
||||
Assert.Equal(typeof(int), m.ModelType);
|
||||
|
|
@ -88,7 +84,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
// Assert
|
||||
var binder = Assert.IsType<CollectionModelBinder<int>>(result);
|
||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
||||
Assert.True(binder.AllowValidatingTopLevelNodes);
|
||||
}
|
||||
|
||||
private class Person
|
||||
|
|
|
|||
|
|
@ -55,17 +55,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
Assert.IsType<ComplexTypeModelBinder>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void Create_ForSupportedType_ReturnsBinder_WithExpectedAllowValidatingTopLevelNodes(
|
||||
bool allowValidatingTopLevelNodes)
|
||||
[Fact]
|
||||
public void Create_ForSupportedType_ReturnsBinder()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new ComplexTypeModelBinderProvider();
|
||||
|
||||
var context = new TestModelBinderProviderContext(typeof(Person));
|
||||
context.MvcOptions.AllowValidatingTopLevelNodes = allowValidatingTopLevelNodes;
|
||||
context.OnCreatingBinder(m =>
|
||||
{
|
||||
if (m.ModelType == typeof(int) || m.ModelType == typeof(string))
|
||||
|
|
@ -83,8 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
var result = provider.GetBinder(context);
|
||||
|
||||
// Assert
|
||||
var binder = Assert.IsType<ComplexTypeModelBinder>(result);
|
||||
Assert.Equal(allowValidatingTopLevelNodes, binder.AllowValidatingTopLevelNodes);
|
||||
Assert.IsType<ComplexTypeModelBinder>(result);
|
||||
}
|
||||
|
||||
private class Person
|
||||
|
|
|
|||
|
|
@ -57,40 +57,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
var result = provider.GetBinder(context);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<DictionaryModelBinder<string, int>>(result);
|
||||
}
|
||||
|
||||
[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);
|
||||
var binder = Assert.IsType<DictionaryModelBinder<string, int>>(result);
|
||||
Assert.False(binder.AllowValidatingTopLevelNodes); // work done in DictionaryModelBinder.
|
||||
}
|
||||
|
||||
private class Person
|
||||
|
|
|
|||
|
|
@ -349,11 +349,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
[InlineData(false, false)]
|
||||
[InlineData(false, true)]
|
||||
[InlineData(true, false)]
|
||||
[InlineData(true, true)]
|
||||
public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
|
||||
bool allowValidatingTopLevelNodes,
|
||||
bool isBindingRequired)
|
||||
{
|
||||
// Arrange
|
||||
var expectedErrorCount = isBindingRequired ? 1 : 0;
|
||||
var binder = new DictionaryModelBinder<string, string>(
|
||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
|
||||
|
|
@ -383,7 +385,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
// Assert
|
||||
Assert.Empty(Assert.IsType<Dictionary<string, string>>(bindingContext.Result.Model));
|
||||
Assert.True(bindingContext.Result.IsModelSet);
|
||||
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
|
||||
Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -14,55 +14,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
{
|
||||
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
|
||||
{
|
||||
get
|
||||
|
|
@ -227,13 +178,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
Assert.Null(result);
|
||||
}
|
||||
|
||||
private TestModelBinderProviderContext GetTestModelBinderProviderContext(
|
||||
Type modelType,
|
||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
||||
private TestModelBinderProviderContext GetTestModelBinderProviderContext(Type modelType)
|
||||
{
|
||||
var context = new TestModelBinderProviderContext(modelType);
|
||||
var options = context.Services.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
options.AllowBindingHeaderValuesToNonStringModelTypes = allowBindingHeaderValuesToNonStringModelTypes;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
{
|
||||
get
|
||||
{
|
||||
var data = new TheoryData<HeaderModelBinder>();
|
||||
var data = new TheoryData<HeaderModelBinder>
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
data.Add(new HeaderModelBinder());
|
||||
new HeaderModelBinder(),
|
||||
#pragma warning restore CS0618
|
||||
data.Add(new HeaderModelBinder(NullLoggerFactory.Instance));
|
||||
new HeaderModelBinder(NullLoggerFactory.Instance),
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
@ -175,11 +178,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(CarType?), null)]
|
||||
[InlineData(typeof(int?), null)]
|
||||
public async Task HeaderBinder_DoesNotSetModel_ForHeaderNotPresentOnRequest(
|
||||
Type modelType,
|
||||
object expectedModel)
|
||||
[InlineData(typeof(CarType?))]
|
||||
[InlineData(typeof(int?))]
|
||||
public async Task HeaderBinder_DoesNotSetModel_ForHeaderNotPresentOnRequest(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
var bindingContext = CreateContext(modelType);
|
||||
|
|
@ -194,11 +195,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(typeof(string[]), null)]
|
||||
[InlineData(typeof(IEnumerable<string>), null)]
|
||||
public async Task HeaderBinder_DoesNotCreateEmptyCollection_ForNonTopLevelObjects(
|
||||
Type modelType,
|
||||
object expectedModel)
|
||||
[InlineData(typeof(string[]))]
|
||||
[InlineData(typeof(IEnumerable<string>))]
|
||||
public async Task HeaderBinder_DoesNotCreateEmptyCollection_ForNonTopLevelObjects(Type modelType)
|
||||
{
|
||||
// Arrange
|
||||
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);
|
||||
}
|
||||
|
||||
private static DefaultModelBindingContext CreateContext(
|
||||
Type modelType,
|
||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
||||
private static DefaultModelBindingContext CreateContext(Type modelType)
|
||||
{
|
||||
return CreateContext(
|
||||
metadata: GetMetadataForType(modelType),
|
||||
valueProvider: null,
|
||||
allowBindingHeaderValuesToNonStringModelTypes: allowBindingHeaderValuesToNonStringModelTypes);
|
||||
return CreateContext(metadata: GetMetadataForType(modelType), valueProvider: null);
|
||||
}
|
||||
|
||||
private static DefaultModelBindingContext CreateContext(
|
||||
ModelMetadata metadata,
|
||||
IValueProvider valueProvider = null,
|
||||
bool allowBindingHeaderValuesToNonStringModelTypes = true)
|
||||
IValueProvider valueProvider = null)
|
||||
{
|
||||
if (valueProvider == null)
|
||||
{
|
||||
valueProvider = Mock.Of<IValueProvider>();
|
||||
}
|
||||
|
||||
var options = new MvcOptions()
|
||||
{
|
||||
AllowBindingHeaderValuesToNonStringModelTypes = allowBindingHeaderValuesToNonStringModelTypes
|
||||
};
|
||||
var options = new MvcOptions();
|
||||
var setup = new MvcCoreMvcOptionsSetup(new TestHttpRequestStreamReaderFactory());
|
||||
setup.Configure(options);
|
||||
|
||||
|
|
@ -452,4 +442,4 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
Coupe
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
{
|
||||
public class ParameterBinderTest
|
||||
{
|
||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
});
|
||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(new MvcOptions());
|
||||
|
||||
public static TheoryData BindModelAsyncData
|
||||
{
|
||||
|
|
@ -211,37 +208,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
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]
|
||||
public async Task BindModelAsync_EnforcesTopLevelRequired()
|
||||
{
|
||||
|
|
@ -280,43 +246,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
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
|
||||
{
|
||||
get
|
||||
|
|
|
|||
|
|
@ -598,17 +598,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadAsync_DefaultOptions_DoesNotWrapJsonInputExceptions()
|
||||
public async Task ReadAsync_DoNotAllowInputFormatterExceptionMessages_DoesNotWrapJsonInputExceptions()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new JsonInputFormatter(
|
||||
GetLogger(),
|
||||
_serializerSettings,
|
||||
ArrayPool<char>.Shared,
|
||||
_objectPoolProvider,
|
||||
new MvcOptions(),
|
||||
new MvcJsonOptions());
|
||||
|
||||
var formatter = CreateFormatter(allowInputFormatterExceptionMessages: false);
|
||||
var contentBytes = Encoding.UTF8.GetBytes("{");
|
||||
var httpContext = GetHttpContext(contentBytes);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/Administration/EitherCookie");
|
||||
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);
|
||||
|
||||
// Assert 2
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
|
||||
var actionContext = new ActionContext(GetHttpContext(), new RouteData(), new ControllerActionDescriptor());
|
||||
|
||||
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, action.Filters);
|
||||
var authorizationFilterContext = new AuthorizationFilterContext(actionContext, new[] { authorizeFilter });
|
||||
|
||||
// Act
|
||||
await authorizeFilter.OnAuthorizationAsync(authorizationFilterContext);
|
||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
var authorizeData = action.Attributes.OfType<AuthorizeAttribute>();
|
||||
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);
|
||||
|
||||
|
|
@ -89,11 +89,13 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
@ -108,11 +110,11 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
return context;
|
||||
}
|
||||
|
||||
private static IServiceProvider GetServices(bool combineAuthorize)
|
||||
private static IServiceProvider GetServices()
|
||||
{
|
||||
var serviceCollection = new ServiceCollection();
|
||||
serviceCollection.AddAuthorization();
|
||||
serviceCollection.AddMvc(o => o.AllowCombiningAuthorizeFilters = combineAuthorize);
|
||||
serviceCollection.AddMvc();
|
||||
serviceCollection
|
||||
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
|
||||
.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.
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
[ModelBinder(BinderType = typeof(Address3ModelBinder))]
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
}
|
||||
|
||||
ModelMetadata metadata;
|
||||
if (optionsAccessor.Value.AllowValidatingTopLevelNodes &&
|
||||
modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||
if (modelMetadataProvider is ModelMetadataProvider modelMetadataProviderBase &&
|
||||
parameterInfo != null)
|
||||
{
|
||||
metadata = modelMetadataProviderBase.GetMetadataForParameter(parameterInfo);
|
||||
|
|
|
|||
|
|
@ -50,4 +50,4 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
|
||||
public MvcOptions Value { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1705,7 +1705,8 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
public async Task FromBody_JToken_ExcludedFromValidation()
|
||||
{
|
||||
// Arrange
|
||||
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(new TestMvcOptions().Value);
|
||||
var options = new TestMvcOptions().Value;
|
||||
var parameterBinder = ModelBindingTestHelper.GetParameterBinder(options);
|
||||
var parameter = new ParameterDescriptor
|
||||
{
|
||||
Name = "Parameter1",
|
||||
|
|
@ -1718,11 +1719,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
|||
};
|
||||
|
||||
var testContext = ModelBindingTestHelper.GetTestContext(
|
||||
request =>
|
||||
updateRequest: request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ message: \"Hello\" }"));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
},
|
||||
mvcOptions: options);
|
||||
|
||||
var httpContext = testContext.HttpContext;
|
||||
var modelState = testContext.ModelState;
|
||||
|
|
|
|||
|
|
@ -169,11 +169,12 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
{
|
||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
|
||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||
|
||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||
defaultProvider.OnProvidersExecuting(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
|
||||
{
|
||||
public void OnPost(string name, [ModelBinder(Name = "personId")] int id) { }
|
||||
|
|
@ -1078,8 +1042,8 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
// Arrange
|
||||
var provider = new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new MvcOptions()),
|
||||
Options.Create(new RazorPagesOptions()));
|
||||
|
||||
var typeInfo = typeof(object).GetTypeInfo();
|
||||
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
|
||||
|
||||
|
|
@ -1225,7 +1189,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
{
|
||||
return new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new MvcOptions { AllowValidatingTopLevelNodes = true }),
|
||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Reflection;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
|
|
@ -145,11 +144,12 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
|||
{
|
||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
Options.Create(new MvcOptions()),
|
||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
||||
|
||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||
defaultProvider.OnProvidersExecuting(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
|
@ -461,10 +460,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
|
||||
var modelMetadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var modelBinderFactory = TestModelBinderFactory.CreateDefault();
|
||||
var mvcOptions = new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
};
|
||||
var mvcOptions = new MvcOptions();
|
||||
|
||||
var parameterBinder = new ParameterBinder(
|
||||
modelMetadataProvider,
|
||||
|
|
|
|||
|
|
@ -1544,15 +1544,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
}
|
||||
|
||||
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
|
||||
var mvcOptions = new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
};
|
||||
var mvcOptions = new MvcOptions();
|
||||
|
||||
return new ParameterBinder(
|
||||
metadataProvider,
|
||||
factory,
|
||||
new DefaultObjectValidator(metadataProvider, new[] { validator }, new MvcOptions()),
|
||||
new DefaultObjectValidator(metadataProvider, new[] { validator }, mvcOptions),
|
||||
Options.Create(mvcOptions),
|
||||
NullLoggerFactory.Instance);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
{
|
||||
public class PageBinderFactoryTest
|
||||
{
|
||||
private static readonly MvcOptions _options = new MvcOptions
|
||||
{
|
||||
AllowValidatingTopLevelNodes = true,
|
||||
};
|
||||
private static readonly MvcOptions _options = new MvcOptions();
|
||||
private static readonly IOptions<MvcOptions> _optionsAccessor = Options.Create(_options);
|
||||
|
||||
[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)
|
||||
{
|
||||
var handlerMethodInfo = type.GetMethod(method);
|
||||
|
|
@ -923,24 +870,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
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
|
||||
{
|
||||
[ModelBinder]
|
||||
|
|
|
|||
|
|
@ -43,20 +43,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.True(mvcOptions.AllowBindingHeaderValuesToNonStringModelTypes);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
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(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
||||
Assert.False(apiBehaviorOptions.AllowInferringBindingSourceForCollectionTypesAsFromQuery);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -81,20 +73,12 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.True(mvcOptions.AllowBindingHeaderValuesToNonStringModelTypes);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
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(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
|
||||
Assert.False(apiBehaviorOptions.AllowInferringBindingSourceForCollectionTypesAsFromQuery);
|
||||
}
|
||||
|
||||
// This just does the minimum needed to be able to resolve these options.
|
||||
|
|
|
|||
|
|
@ -389,13 +389,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
typeof(RazorPagesOptionsConfigureCompatibilityOptions),
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(IPostConfigureOptions<MvcJsonOptions>),
|
||||
new[]
|
||||
{
|
||||
typeof(MvcJsonOptionsConfigureCompatibilityOptions),
|
||||
}
|
||||
},
|
||||
{
|
||||
typeof(IActionConstraintProvider),
|
||||
new Type[]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace BasicWebSite
|
|||
services.AddRouting();
|
||||
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest) // this compat version enables endpoint routing
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest)
|
||||
.AddXmlDataContractSerializerFormatters();
|
||||
|
||||
services.ConfigureBaseWebSiteAuthPolicies();
|
||||
|
|
@ -45,4 +45,4 @@ namespace BasicWebSite
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ namespace SecurityWebSite.Controllers
|
|||
return Content("Administration.Index");
|
||||
}
|
||||
|
||||
// Either cookie should allow access to this action (if AllowCombiningAuthorizeFilters is true)
|
||||
// If AllowCombiningAuthorizeFilters is false, the main cookie is required.
|
||||
// Either cookie should allow access to this action.
|
||||
[Authorize(AuthenticationSchemes = "Cookie2")]
|
||||
public IActionResult EitherCookie()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue