Remove remaining `CompatibilitySwitch<T>` properties

- #4866 3 of 3
- other than ignored parameters and properties, no vestige remains of alternate behaviours
- also remove `AllowAreas` use outside src/Mvc
- left the `IEnumerable<ICompatibilitySwitch>` implementations to avoid `breakingchanges.netcore.json` churn
  - made the implementations more consistent
- left one `ConfigureCompatibilityOptions<MvcOptions>` subclass: `MvcOptionsConfigureCompatibilityOptions`
- note `AllowShortCircuitingValidationWhenNoValidatorsArePresent` default now applies to `TryValidateModel(...)` etc.

nits:
- updated `CompatibilityVersion` doc comments
- "currently unused" -> "currently ignored" in doc comments from part 2
- took a few VS suggestions
- VS seems to have cleaned up some trailing whitespace in files I had opened but didn't manually change
This commit is contained in:
Doug Bunting 2018-12-13 22:59:45 -08:00 committed by Doug Bunting
parent db0c347c23
commit f113a20dfd
63 changed files with 246 additions and 1243 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.using Microsoft.AspNetCore.Authorization;
using System;
@ -192,7 +192,6 @@ namespace Microsoft.AspNetCore.Authentication
var additionalParts = GetAdditionalParts();
var mvcBuilder = services
.AddMvc()
.AddRazorPagesOptions(o => o.AllowAreas = true)
.ConfigureApplicationPartManager(apm =>
{
foreach (var part in additionalParts)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.using Microsoft.AspNetCore.Authorization;
using System;
@ -193,7 +193,6 @@ namespace Microsoft.AspNetCore.Authentication
var additionalParts = GetAdditionalParts();
var mvcBuilder = services
.AddMvc()
.AddRazorPagesOptions(o => o.AllowAreas = true)
.ConfigureApplicationPartManager(apm =>
{
foreach (var part in additionalParts)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
@ -37,7 +37,6 @@ namespace Microsoft.AspNetCore.Identity.UI
name = name ?? throw new ArgumentNullException(nameof(name));
options = options ?? throw new ArgumentNullException(nameof(options));
options.AllowAreas = true;
options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");
options.Conventions.AuthorizeAreaPage(IdentityUIDefaultAreaName, "/Account/Logout");
var convention = new IdentityPageModelConvention<TUser>();

View File

@ -7,8 +7,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// Defines the set of policies that determine how the model binding system interprets exceptions
/// thrown by an <see cref="IInputFormatter"/>. Applications should set
/// <c>MvcOptions.InputFormatterExceptionPolicy</c> to configure this setting.
/// thrown by an <see cref="IInputFormatter"/>. <seealso cref="IInputFormatterExceptionPolicy"/>
/// </summary>
/// <remarks>
/// <para>
@ -25,12 +24,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
/// The policy associated with <see cref="InputFormatterExceptionPolicy.AllExceptions"/> treats
/// all such categories of problems as model state errors, and usually will be reported to the client as
/// an HTTP 400. This was the only policy supported by model binding in ASP.NET Core MVC 1.0, 1.1, and 2.0
/// and is still the default for historical reasons.
/// and is still the default for historical reasons.
/// </para>
/// <para>
/// The policy associated with <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>
/// treats only <see cref="InputFormatterException"/> and its subclasses as model state errors. This means that
/// exceptions that are not related to the content of the HTTP request (such as a disconnect) will be rethrown,
/// exceptions that are not related to the content of the HTTP request (such as a disconnect) will be re-thrown,
/// which by default would cause an HTTP 500 response, unless there is exception-handling middleware enabled.
/// </para>
/// </remarks>
@ -44,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
/// <summary>
/// This value indicates that only <see cref="InputFormatterException"/> and subclasses will be treated
/// as model state errors. All other exceptions types will be rethrown and can be handled by a higher
/// as model state errors. All other exceptions types will be re-thrown and can be handled by a higher
/// level exception handler, such as exception-handling middleware.
/// </summary>
MalformedInputExceptions = 1,

View File

@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
/// constraints.</param>
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
/// <remarks>The <paramref name="mapper"/> parameter is currently ignored.</remarks>
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
public DefaultApiDescriptionProvider(
IOptions<MvcOptions> optionsAccessor,
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</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>
/// <remarks>The <paramref name="mapper"/> parameter is currently ignored.</remarks>
public DefaultApiDescriptionProvider(
IOptions<MvcOptions> optionsAccessor,
IInlineConstraintResolver constraintResolver,

View File

@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public class ApiBehaviorOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
private Func<ActionContext, IActionResult> _invalidModelStateResponseFactory;
/// <summary>
@ -84,10 +84,7 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } = new Dictionary<int, ClientErrorData>();
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -52,14 +52,8 @@ namespace Microsoft.AspNetCore.Mvc
/// ASP.NET Core MVC 2.1.
/// </summary>
/// <remarks>
/// ASP.NET Core MVC 2.1 introduced compatibility switches for the following:
/// <list type="bullet">
/// <item><description><see cref="MvcOptions.InputFormatterExceptionPolicy"/></description></item>
/// <item><description><see cref="MvcOptions.SuppressBindingUndefinedValueToEnumType"/></description></item>
/// <item><description><c>MvcJsonOptions.AllowInputFormatterExceptionMessages</c></description></item>
/// <item><description><c>RazorPagesOptions.AllowAreas</c></description></item>
/// <item><description><c>RazorPagesOptions.AllowMappingHeadRequestsToGetHandler</c></description></item>
/// </list>
/// ASP.NET Core MVC 2.1 introduced a compatibility switch for
/// <c>MvcJsonOptions.AllowInputFormatterExceptionMessages</c>. This is now a regular property.
/// </remarks>
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
nameof(Version_3_0) + " or later.")]
@ -73,15 +67,10 @@ 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>MvcDataAnnotationsLocalizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes</c></description></item>
/// <item><description><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
/// <item><description><see cref="MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent"/></description></item>
/// <item><description><see cref="MvcOptions.MaxValidationDepth" /></description></item>
/// <item><description><c>RazorPagesOptions.AllowDefaultHandlingForOptionsRequests</c></description></item>
/// <item><description><c>RazorViewEngineOptions.AllowRecompilingViewsOnFileChange</c></description></item>
/// <item><description><c>MvcViewOptions.AllowRenderingMaxLengthAttribute</c></description></item>
/// <item><description><c>MvcXmlOptions.AllowRfc7807CompliantProblemDetailsFormat</c></description></item>
/// </list>
/// All of the above are now regular properties.
/// </remarks>
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
nameof(Version_3_0) + " or later.")]

View File

@ -2,7 +2,6 @@
// 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.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -21,12 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
{
get
{
return new Dictionary<string, object>
{
[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions,
[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true,
[nameof(MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent)] = true,
};
return new Dictionary<string, object>();
}
}
}

View File

@ -192,13 +192,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
private bool ShouldHandleException(IInputFormatter formatter)
{
var policy = _options.InputFormatterExceptionPolicy;
// Any explicit policy on the formatters takes precedence over the global policy on MvcOptions
if (formatter is IInputFormatterExceptionPolicy exceptionPolicy)
{
policy = exceptionPolicy.ExceptionPolicy;
}
// Any explicit policy on the formatters overrides the default.
var policy = (formatter as IInputFormatterExceptionPolicy)?.ExceptionPolicy ??
InputFormatterExceptionPolicy.MalformedInputExceptions;
return policy == InputFormatterExceptionPolicy.AllExceptions;
}

View File

@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
public class EnumTypeModelBinder : SimpleTypeModelBinder
{
private readonly bool _suppressBindingUndefinedValueToEnumType;
/// <summary>
/// Initializes a new instance of <see cref="EnumTypeModelBinder"/>.
/// </summary>
@ -22,6 +20,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </param>
/// <param name="modelType">The model type.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>,</param>
/// <remarks>
/// The <paramref name="suppressBindingUndefinedValueToEnumType"/> parameter is currently ignored.
/// </remarks>
public EnumTypeModelBinder(
bool suppressBindingUndefinedValueToEnumType,
Type modelType,
@ -37,8 +38,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_suppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType;
}
protected override void CheckModel(
@ -46,23 +45,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
ValueProviderResult valueProviderResult,
object model)
{
if (model == null || !_suppressBindingUndefinedValueToEnumType)
if (model == null)
{
base.CheckModel(bindingContext, valueProviderResult, model);
}
else if (IsDefinedInEnum(model, bindingContext))
{
bindingContext.Result = ModelBindingResult.Success(model);
}
else
{
if (IsDefinedInEnum(model, bindingContext))
{
bindingContext.Result = ModelBindingResult.Success(model);
}
else
{
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(
valueProviderResult.ToString()));
}
bindingContext.ModelState.TryAddModelError(
bindingContext.ModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(
valueProviderResult.ToString()));
}
}
@ -70,14 +66,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
var modelType = bindingContext.ModelMetadata.UnderlyingOrModelType;
// Check if the converted value is indeed defined on the enum as EnumTypeConverter
// Check if the converted value is indeed defined on the enum as EnumTypeConverter
// converts value to the backing type (ex: integer) and does not check if the value is defined on the enum.
if (bindingContext.ModelMetadata.IsFlagsEnum)
{
// Enum.IsDefined does not work with combined flag enum values.
// From EnumDataTypeAttribute.cs in CoreFX.
// Examples:
//
//
// [Flags]
// enum FlagsEnum { Value1 = 1, Value2 = 2, Value4 = 4 }
//
@ -87,7 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
//
// Invalid Scenarios:
// 1. valueProviderResult="2,10", model=12, underlying=12, converted=12
//
//
var underlying = Convert.ChangeType(
model,
Enum.GetUnderlyingType(modelType),

View File

@ -12,15 +12,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
public class EnumTypeModelBinderProvider : IModelBinderProvider
{
private readonly MvcOptions _options;
/// <summary>
/// Initializes a new instance of <see cref="EnumTypeModelBinderProvider"/>.
/// </summary>
/// <param name="options">The <see cref="MvcOptions"/>.</param>
/// <remarks>The <paramref name="options"/> parameter is currently ignored.</remarks>
public EnumTypeModelBinderProvider(MvcOptions options)
{
_options = options;
}
/// <inheritdoc />
@ -35,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new EnumTypeModelBinder(
_options.SuppressBindingUndefinedValueToEnumType,
suppressBindingUndefinedValueToEnumType: true,
context.Metadata.UnderlyingOrModelType,
loggerFactory);
}

View File

@ -54,7 +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>
/// <remarks>The <paramref name="mvcOptions"/> parameter is currently ignored.</remarks>
public ParameterBinder(
IModelMetadataProvider modelMetadataProvider,
IModelBinderFactory modelBinderFactory,

View File

@ -42,8 +42,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
validationState)
{
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
AllowShortCircuitingValidationWhenNoValidatorsArePresent =
_mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent,
};
return visitor;

View File

@ -107,7 +107,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
/// Gets or sets a value that determines if <see cref="ValidationVisitor"/> can short circuit validation when a model
/// does not have any associated validators.
/// </summary>
public bool AllowShortCircuitingValidationWhenNoValidatorsArePresent { get; set; }
/// <value>The default value is <see langword="true"/>.</value>
/// <remarks>This property is currently ignored.</remarks>
public bool AllowShortCircuitingValidationWhenNoValidatorsArePresent { get; set; } = true;
/// <summary>
/// Validates a object.
@ -266,9 +268,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
}
// If the metadata indicates that no validators exist AND the aggregate state for the key says that the model graph
// is not invalid (i.e. is one of Unvalidated, Valid, or Skipped) we can safely mark the graph as valid.
else if (
AllowShortCircuitingValidationWhenNoValidatorsArePresent &&
metadata.HasValidators == false &&
else if (metadata.HasValidators == false &&
ModelState.GetFieldValidationState(key) != ModelValidationState.Invalid)
{
// No validators will be created for this graph of objects. Mark it as valid if it wasn't previously validated.

View File

@ -19,12 +19,7 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
{
// See CompatibilitySwitch.cs for guide on how to implement these.
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
private readonly CompatibilitySwitch<bool> _allowShortCircuitingValidationWhenNoValidatorsArePresent;
private readonly ICompatibilitySwitch[] _switches;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
private int? _maxValidationDepth = 32;
@ -44,17 +39,6 @@ namespace Microsoft.AspNetCore.Mvc
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
ModelValidatorProviders = new List<IModelValidatorProvider>();
ValueProviderFactories = new List<IValueProviderFactory>();
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
_allowShortCircuitingValidationWhenNoValidatorsArePresent = new CompatibilitySwitch<bool>(nameof(AllowShortCircuitingValidationWhenNoValidatorsArePresent));
_switches = new ICompatibilitySwitch[]
{
_inputFormatterExceptionPolicy,
_suppressBindingUndefinedValueToEnumType,
_allowShortCircuitingValidationWhenNoValidatorsArePresent,
};
}
/// <summary>
@ -102,36 +86,11 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public FormatterMappings FormatterMappings { get; }
/// <summary>
/// Gets or sets a value which determines how the model binding system interprets exceptions thrown by an <see cref="IInputFormatter"/>.
/// </summary>
/// <value>
/// The default value is <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>.
/// </value>
public InputFormatterExceptionPolicy InputFormatterExceptionPolicy
{
get => _inputFormatterExceptionPolicy.Value;
set => _inputFormatterExceptionPolicy.Value = value;
}
/// <summary>
/// Gets a list of <see cref="IInputFormatter"/>s that are used by this application.
/// </summary>
public FormatterCollection<IInputFormatter> InputFormatters { get; }
/// <summary>
/// Gets or sets a value indicating whether the model binding system will bind undefined values to
/// enum types.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
public bool SuppressBindingUndefinedValueToEnumType
{
get => _suppressBindingUndefinedValueToEnumType.Value;
set => _suppressBindingUndefinedValueToEnumType.Value = value;
}
/// <summary>
/// Gets or sets the flag to buffer the request body in input formatters. Default is <c>false</c>.
/// </summary>
@ -250,30 +209,7 @@ namespace Microsoft.AspNetCore.Mvc
}
}
/// <summary>
/// Gets or sets a value that determines if <see cref="ValidationVisitor"/>
/// can short-circuit validation when a model does not have any associated validators.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
/// <remarks>
/// When <see cref="ModelMetadata.HasValidators"/> is <see langword="true"/>, that is, it is determined
/// that a model or any of it's properties or collection elements cannot have any validators,
/// <see cref="ValidationVisitor"/> can short-circuit validation for the model and mark the object
/// graph as valid. Setting this property to <see langword="true"/>, allows <see cref="ValidationVisitor"/> to
/// perform this optimization.
/// </remarks>
public bool AllowShortCircuitingValidationWhenNoValidatorsArePresent
{
get => _allowShortCircuitingValidationWhenNoValidatorsArePresent.Value;
set => _allowShortCircuitingValidationWhenNoValidatorsArePresent.Value = value;
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -102,5 +102,25 @@
"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"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public Microsoft.AspNetCore.Mvc.Formatters.InputFormatterExceptionPolicy get_InputFormatterExceptionPolicy()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Boolean get_SuppressBindingUndefinedValueToEnumType()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Void set_InputFormatterExceptionPolicy(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterExceptionPolicy value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Void set_SuppressBindingUndefinedValueToEnumType(System.Boolean value)",
"Kind": "Removal"
}
]

View File

@ -27,9 +27,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
<IConfigureOptions<MvcDataAnnotationsLocalizationOptions>,
MvcDataAnnotationsLocalizationOptionsSetup>());
}
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcDataAnnotationsLocalizationOptions>, MvcDataAnnotationsLocalizationConfigureCompatibilityOptions>());
}
}
}

View File

@ -184,16 +184,9 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
var namesAndValues = new Dictionary<string, string>();
IStringLocalizer enumLocalizer = null;
if (_localizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes)
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory);
}
}
else
{
enumLocalizer = _stringLocalizerFactory?.Create(underlyingType);
enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory);
}
var enumFields = Enum.GetNames(underlyingType)

View File

@ -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.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
internal class MvcDataAnnotationsLocalizationConfigureCompatibilityOptions : ConfigureCompatibilityOptions<MvcDataAnnotationsLocalizationOptions>
{
public MvcDataAnnotationsLocalizationConfigureCompatibilityOptions(
ILoggerFactory loggerFactory,
IOptions<MvcCompatibilityOptions> compatibilityOptions)
: base(loggerFactory, compatibilityOptions)
{
}
protected override IReadOnlyDictionary<string, object> DefaultValues
{
get
{
return new Dictionary<string, object>
{
[nameof(MvcDataAnnotationsLocalizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes)] = true,
};
}
}
}
}

View File

@ -14,42 +14,14 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
/// </summary>
public class MvcDataAnnotationsLocalizationOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly CompatibilitySwitch<bool> _allowDataAnnotationsLocalizationForEnumDisplayAttributes;
private readonly ICompatibilitySwitch[] _switches;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
/// <summary>
/// The delegate to invoke for creating <see cref="IStringLocalizer"/>.
/// </summary>
public Func<Type, IStringLocalizerFactory, IStringLocalizer> DataAnnotationLocalizerProvider;
/// <summary>
/// Instantiates a new instance of the <see cref="MvcDataAnnotationsLocalizationOptions"/> class.
/// </summary>
public MvcDataAnnotationsLocalizationOptions()
{
_allowDataAnnotationsLocalizationForEnumDisplayAttributes = new CompatibilitySwitch<bool>(nameof(AllowDataAnnotationsLocalizationForEnumDisplayAttributes));
_switches = new ICompatibilitySwitch[]
{
_allowDataAnnotationsLocalizationForEnumDisplayAttributes
};
}
/// <summary>
/// Gets or sets a value that determines if <see cref="DataAnnotationLocalizerProvider"/> should be used while localizing <see cref="Enum"/> types.
/// If set to <c>true</c> <see cref="DataAnnotationLocalizerProvider"/> will be used in localizing <see cref="Enum"/> types.
/// If set to <c>false</c> the localization will search for values in resource files for the <see cref="Enum"/>.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
public bool AllowDataAnnotationsLocalizationForEnumDisplayAttributes
{
get => _allowDataAnnotationsLocalizationForEnumDisplayAttributes.Value;
set => _allowDataAnnotationsLocalizationForEnumDisplayAttributes.Value = value;
}
public IEnumerator<ICompatibilitySwitch> GetEnumerator() => ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
}
/// <inheritdoc />
public override InputFormatterExceptionPolicy ExceptionPolicy
{
@ -180,4 +180,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
return base.CanRead(context);
}
}
}
}

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
/// <summary>
/// Gets or sets a flag to determine whether error messages from JSON deserialization by the
@ -38,10 +38,7 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public JsonSerializerSettings SerializerSettings { get; } = JsonSerializerSettingsProvider.CreateSerializerSettings();
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -119,9 +119,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
}
// Internal for testing.
@ -129,9 +126,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
}
}
}

View File

@ -120,9 +120,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
}
// Internal for testing.
@ -130,9 +127,6 @@ namespace Microsoft.Extensions.DependencyInjection
{
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
}
}
}

View File

@ -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.Formatters.Xml;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
internal sealed class MvcXmlOptionsConfigureCompatibilityOptions : ConfigureCompatibilityOptions<MvcXmlOptions>
{
public MvcXmlOptionsConfigureCompatibilityOptions(
ILoggerFactory loggerFactory,
IOptions<MvcCompatibilityOptions> compatibilityOptions)
: base(loggerFactory, compatibilityOptions)
{
}
protected override IReadOnlyDictionary<string, object> DefaultValues
{
get
{
return new Dictionary<string, object>
{
[nameof(MvcXmlOptions.AllowRfc7807CompliantProblemDetailsFormat)] = true,
};
}
}
}
}

View File

@ -18,19 +18,14 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
internal sealed class XmlDataContractSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly MvcXmlOptions _xmlOptions;
private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// Initializes a new instance of <see cref="XmlDataContractSerializerMvcOptionsSetup"/>.
/// </summary>
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public XmlDataContractSerializerMvcOptionsSetup(
IOptions<MvcXmlOptions> xmlOptions,
ILoggerFactory loggerFactory)
public XmlDataContractSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
{
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
@ -43,11 +38,11 @@ namespace Microsoft.Extensions.DependencyInjection
options.ModelMetadataDetailsProviders.Add(new DataMemberRequiredBindingMetadataProvider());
var inputFormatter = new XmlDataContractSerializerInputFormatter(options);
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
options.InputFormatters.Add(inputFormatter);
var outputFormatter = new XmlDataContractSerializerOutputFormatter(_loggerFactory);
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
options.OutputFormatters.Add(outputFormatter);
// Do not override any user mapping

View File

@ -16,19 +16,14 @@ namespace Microsoft.Extensions.DependencyInjection
/// </summary>
internal sealed class XmlSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly MvcXmlOptions _xmlOptions;
private readonly ILoggerFactory _loggerFactory;
/// <summary>
/// Initializes a new instance of <see cref="XmlSerializerMvcOptionsSetup"/>.
/// </summary>
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public XmlSerializerMvcOptionsSetup(
IOptions<MvcXmlOptions> xmlOptions,
ILoggerFactory loggerFactory)
public XmlSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
{
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
@ -49,11 +44,11 @@ namespace Microsoft.Extensions.DependencyInjection
}
var inputFormatter = new XmlSerializerInputFormatter(options);
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
options.InputFormatters.Add(inputFormatter);
var outputFormatter = new XmlSerializerOutputFormatter(_loggerFactory);
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
options.OutputFormatters.Add(outputFormatter);
}

View File

@ -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.Infrastructure;
@ -10,39 +11,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
/// <summary>
/// Provides configuration for XML formatters.
/// </summary>
/// <remarks>This class is currently empty.</remarks>
public class MvcXmlOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly CompatibilitySwitch<bool> _allowRfc7807CompliantProblemDetailsFormat;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
/// <summary>
/// Creates a new instance of <see cref="MvcXmlOptions"/>.
/// </summary>
public MvcXmlOptions()
{
_allowRfc7807CompliantProblemDetailsFormat = new CompatibilitySwitch<bool>(nameof(AllowRfc7807CompliantProblemDetailsFormat));
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
_switches = new ICompatibilitySwitch[]
{
_allowRfc7807CompliantProblemDetailsFormat,
};
}
/// <summary>
/// Gets or sets a value inidicating whether <see cref="ProblemDetails"/> and <see cref="ValidationProblemDetails"/>
/// are serialized in a format compliant with the RFC 7807 specification (https://tools.ietf.org/html/rfc7807).
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
public bool AllowRfc7807CompliantProblemDetailsFormat
{
get => _allowRfc7807CompliantProblemDetailsFormat.Value;
set => _allowRfc7807CompliantProblemDetailsFormat.Value = value;
}
public IEnumerator<ICompatibilitySwitch> GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}
}

View File

@ -7,41 +7,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
{
internal class ProblemDetailsWrapperProviderFactory : IWrapperProviderFactory
{
private readonly MvcXmlOptions _options;
public ProblemDetailsWrapperProviderFactory(MvcXmlOptions options)
{
_options = options;
}
public IWrapperProvider GetProvider(WrapperProviderContext context)
{
if (context.DeclaredType == typeof(ProblemDetails))
{
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
{
return new WrapperProvider(typeof(ProblemDetailsWrapper), p => new ProblemDetailsWrapper((ProblemDetails)p));
}
else
{
#pragma warning disable CS0618 // Type or member is obsolete
return new WrapperProvider(typeof(ProblemDetails21Wrapper), p => new ProblemDetails21Wrapper((ProblemDetails)p));
#pragma warning restore CS0618 // Type or member is obsolete
}
return new WrapperProvider(typeof(ProblemDetailsWrapper), p => new ProblemDetailsWrapper((ProblemDetails)p));
}
if (context.DeclaredType == typeof(ValidationProblemDetails))
{
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
{
return new WrapperProvider(typeof(ValidationProblemDetailsWrapper), p => new ValidationProblemDetailsWrapper((ValidationProblemDetails)p));
}
else
{
#pragma warning disable CS0618 // Type or member is obsolete
return new WrapperProvider(typeof(ValidationProblemDetails21Wrapper), p => new ValidationProblemDetails21Wrapper((ValidationProblemDetails)p));
#pragma warning restore CS0618 // Type or member is obsolete
}
return new WrapperProvider(typeof(ValidationProblemDetailsWrapper), p => new ValidationProblemDetailsWrapper((ValidationProblemDetails)p));
}
return null;
@ -62,4 +37,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
public object Wrap(object original) => WrapDelegate(original);
}
}
}
}

View File

@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
// When RootDirectory and AreaRootDirectory overlap (e.g. RootDirectory = '/', AreaRootDirectory = '/Areas'), we
// only want to allow a page to be associated with the area route.
if (_pagesOptions.AllowAreas && relativePath.StartsWith(areaRootDirectory, StringComparison.OrdinalIgnoreCase))
if (relativePath.StartsWith(areaRootDirectory, StringComparison.OrdinalIgnoreCase))
{
routeModel = _routeModelFactory.CreateAreaRouteModel(relativePath, routeTemplate);
}

View File

@ -179,10 +179,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
pageModel.Filters.Add(_pageHandlerResultFilter);
}
if (_razorPagesOptions.AllowDefaultHandlingForOptionsRequests)
{
pageModel.Filters.Add(_handleOptionsRequestsFilter);
}
pageModel.Filters.Add(_handleOptionsRequestsFilter);
}
/// <summary>

View File

@ -5,7 +5,6 @@ using System;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
@ -82,8 +81,6 @@ namespace Microsoft.Extensions.DependencyInjection
// Options
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorPagesRazorViewEngineOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<RazorPagesOptions>, RazorPagesOptionsConfigureCompatibilityOptions>());
// Action description and invocation
services.TryAddEnumerable(

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
@ -13,20 +12,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
private const string Handler = "handler";
private readonly IOptions<RazorPagesOptions> _options;
public DefaultPageHandlerMethodSelector(IOptions<RazorPagesOptions> options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
_options = options;
}
private bool AllowFuzzyHttpMethodMatching => _options?.Value.AllowMappingHeadRequestsToGetHandler ?? false;
public HandlerMethodDescriptor Select(PageContext context)
{
var handlers = SelectHandlers(context);
@ -113,7 +98,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
}
// Step 1a: do fuzzy HTTP method matching if needed.
if (candidates.Count == 0 && AllowFuzzyHttpMethodMatching)
if (candidates.Count == 0)
{
var fuzzyHttpMethod = GetFuzzyMatchHttpMethod(context);
if (fuzzyHttpMethod != null)

View File

@ -14,27 +14,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// </summary>
public class RazorPagesOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly CompatibilitySwitch<bool> _allowAreas;
private readonly CompatibilitySwitch<bool> _allowMappingHeadRequestsToGetHandler;
private readonly CompatibilitySwitch<bool> _allowsDefaultHandlingForOptionsRequests;
private readonly ICompatibilitySwitch[] _switches;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
private string _root = "/Pages";
public RazorPagesOptions()
{
_allowAreas = new CompatibilitySwitch<bool>(nameof(AllowAreas));
_allowMappingHeadRequestsToGetHandler = new CompatibilitySwitch<bool>(nameof(AllowMappingHeadRequestsToGetHandler));
_allowsDefaultHandlingForOptionsRequests = new CompatibilitySwitch<bool>(nameof(AllowDefaultHandlingForOptionsRequests));
_switches = new ICompatibilitySwitch[]
{
_allowAreas,
_allowMappingHeadRequestsToGetHandler,
_allowsDefaultHandlingForOptionsRequests,
};
}
/// <summary>
/// Gets a collection of <see cref="IPageConvention"/> instances that are applied during
/// route and page model construction.
@ -64,70 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
}
}
/// <summary>
/// Gets or sets a value that determines if areas are enabled for Razor Pages.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
/// <remarks>
/// When enabled, any Razor Page under the directory structure <c>/Area/AreaName/Pages/</c>
/// will be associated with an area with the name <c>AreaName</c>.
/// </remarks>
public bool AllowAreas
{
get => _allowAreas.Value;
set => _allowAreas.Value = value;
}
/// <summary>
/// Gets or sets a value that determines if HTTP method matching for Razor Pages handler methods will use
/// fuzzy matching.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
/// <remarks>
/// <para>
/// When enabled, Razor Pages handler methods will be more flexible in which HTTP methods will be accepted
/// by GET and POST handler methods. This allows a GET handler methods to accept the HEAD HTTP methods in
/// addition to GET. A more specific handler method can still be defined to accept HEAD, and the most
/// specific handler will be invoked.
/// </para>
/// <para>
/// This setting reduces the number of handler methods that must be written to correctly respond to typical
/// web traffic including requests from internet infrastructure such as web crawlers.
/// </para>
/// </remarks>
public bool AllowMappingHeadRequestsToGetHandler
{
get => _allowMappingHeadRequestsToGetHandler.Value;
set => _allowMappingHeadRequestsToGetHandler.Value = value;
}
/// <summary>
/// Gets or sets a value that determines if HTTP requests with the OPTIONS method are handled by default, if
/// no handler is available.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
/// <remarks>
/// Razor Pages uses the current request's HTTP method to select a handler method. When no handler is available or selected,
/// the page is immediately executed. This may cause runtime errors if the page relies on the handler method to execute
/// and initialize some state. This setting attempts to avoid this class of error for HTTP <c>OPTIONS</c> requests by
/// returning a <c>200 OK</c> response.
/// </remarks>
public bool AllowDefaultHandlingForOptionsRequests
{
get => _allowsDefaultHandlingForOptionsRequests.Value;
set => _allowsDefaultHandlingForOptionsRequests.Value = value;
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -1,33 +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.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.RazorPages
{
internal class RazorPagesOptionsConfigureCompatibilityOptions : ConfigureCompatibilityOptions<RazorPagesOptions>
{
public RazorPagesOptionsConfigureCompatibilityOptions(
ILoggerFactory loggerFactory,
IOptions<MvcCompatibilityOptions> compatibilityOptions)
: base(loggerFactory, compatibilityOptions)
{
}
protected override IReadOnlyDictionary<string, object> DefaultValues
{
get
{
return new Dictionary<string, object>
{
[nameof(RazorPagesOptions.AllowAreas)] = true,
[nameof(RazorPagesOptions.AllowMappingHeadRequestsToGetHandler)] = true,
[nameof(RazorPagesOptions.AllowDefaultHandlingForOptionsRequests)] = true,
};
}
}
}
}

View File

@ -27,5 +27,25 @@
{
"TypeId": "public static class Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageDirectiveFeature",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Boolean get_AllowAreas()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Boolean get_AllowMappingHeadRequestsToGetHandler()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Void set_AllowAreas(System.Boolean value)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Void set_AllowMappingHeadRequestsToGetHandler(System.Boolean value)",
"Kind": "Removal"
}
]
]

View File

@ -95,17 +95,24 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Underscores are fine characters in id's.
IdAttributeDotReplacement = optionsAccessor.Value.HtmlHelperOptions.IdAttributeDotReplacement;
AllowRenderingMaxLengthAttribute = optionsAccessor.Value.AllowRenderingMaxLengthAttribute;
}
/// <summary>
/// Gets or sets a value that indicates whether the maxlength attribute should be rendered for compatible HTML input elements,
/// when they're bound to models marked with either
/// <see cref="StringLengthAttribute"/> or <see cref="MaxLengthAttribute"/> attributes.
/// <summary>
/// Gets or sets a value that indicates whether the <c>maxlength</c> attribute should be rendered for
/// compatible HTML input elements, when they're bound to models marked with either
/// <see cref="StringLengthAttribute"/> or <see cref="MaxLengthAttribute"/> attributes.
/// </summary>
/// <remarks>If both attributes are specified, the one with the smaller value will be used for the rendered `maxlength` attribute.</remarks>
protected bool AllowRenderingMaxLengthAttribute { get; }
/// <value>The default value is <see langword="true"/>.</value>
/// <remarks>
/// <para>
/// If both attributes are specified, the one with the smaller value will be used for the rendered
/// <c>maxlength</c> attribute.
/// </para>
/// <para>
/// This property is currently ignored.
/// </para>
/// </remarks>
protected bool AllowRenderingMaxLengthAttribute { get; } = true;
/// <inheritdoc />
public string IdAttributeDotReplacement { get; }
@ -737,11 +744,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
AddPlaceholderAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
if (AllowRenderingMaxLengthAttribute)
{
AddMaxLengthAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
}
AddMaxLengthAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
AddValidationAttributes(viewContext, tagBuilder, modelExplorer, expression);
// If there are any errors for a named field, we add this CSS attribute.
@ -1257,7 +1260,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
AddPlaceholderAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
}
if (AllowRenderingMaxLengthAttribute && _maxLengthInputTypes.Contains(suppliedTypeString))
if (_maxLengthInputTypes.Contains(suppliedTypeString))
{
AddMaxLengthAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
}
@ -1397,7 +1400,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
/// <summary>
/// Adds a maxlength attribute to the <paramref name="tagBuilder" />.
/// Adds a <c>maxlength</c> attribute to the <paramref name="tagBuilder" />.
/// </summary>
/// <param name="viewData">A <see cref="ViewDataDictionary"/> instance for the current scope.</param>
/// <param name="tagBuilder">A <see cref="TagBuilder"/> instance.</param>
@ -1552,8 +1555,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
// Second check the Eval() call returned a collection of SelectListItems.
var selectList = value as IEnumerable<SelectListItem>;
if (selectList == null)
if (!(value is IEnumerable<SelectListItem> selectList))
{
throw new InvalidOperationException(Resources.FormatHtmlHelper_WrongSelectDataType(
expression,
@ -1606,8 +1608,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
IEnumerable<SelectListItem> selectList,
ICollection<string> currentValues)
{
var itemsList = selectList as IList<SelectListItem>;
if (itemsList == null)
if (!(selectList is IList<SelectListItem> itemsList))
{
itemsList = selectList.ToList();
}

View File

@ -143,8 +143,6 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IPostConfigureOptions<MvcViewOptions>, MvcViewOptionsConfigureCompatibilityOptions>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());

View File

@ -85,10 +85,6 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
List<LifecycleProperty> results = null;
var propertyHelpers = PropertyHelper.GetVisibleProperties(type: type);
var prefix = viewOptions.SuppressTempDataAttributePrefix ?
string.Empty :
"TempDataProperty-";
for (var i = 0; i < propertyHelpers.Length; i++)
{
var propertyHelper = propertyHelpers[i];
@ -105,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
var key = tempDataAttribute.Key;
if (string.IsNullOrEmpty(key))
{
key = prefix + property.Name;
key = property.Name;
}
results.Add(new LifecycleProperty(property, key));

View File

@ -4,7 +4,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.ViewEngines;
@ -17,22 +16,9 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public class MvcViewOptions : IEnumerable<ICompatibilitySwitch>
{
private readonly CompatibilitySwitch<bool> _suppressTempDataAttributePrefix;
private readonly CompatibilitySwitch<bool> _allowRenderingMaxLengthAttribute;
private readonly ICompatibilitySwitch[] _switches;
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
private HtmlHelperOptions _htmlHelperOptions = new HtmlHelperOptions();
public MvcViewOptions()
{
_suppressTempDataAttributePrefix = new CompatibilitySwitch<bool>(nameof(SuppressTempDataAttributePrefix));
_allowRenderingMaxLengthAttribute = new CompatibilitySwitch<bool>(nameof(AllowRenderingMaxLengthAttribute));
_switches = new[]
{
_suppressTempDataAttributePrefix,
_allowRenderingMaxLengthAttribute
};
}
/// <summary>
/// Gets or sets programmatic configuration for the HTML helpers and <see cref="Rendering.ViewContext"/>.
/// </summary>
@ -50,45 +36,6 @@ namespace Microsoft.AspNetCore.Mvc
}
}
/// <summary>
/// <para>
/// Gets or sets a value that determines if the <see cref="ITempDataDictionary"/> keys for
/// properties annotated with <see cref="TempDataAttribute"/> include the prefix <c>TempDataProperty-</c>.
/// </para>
/// <para>
/// When <see cref="TempDataAttribute.Key"/> is not specified, the lookup key for properties annotated
/// with <see cref="TempDataAttribute"/> is derived from the property name. In releases prior to ASP.NET Core 2.1,
/// the calculated key was the property name prefixed by the value <c>TempDataProperty-</c>.
/// e.g. <c>TempDataProperty-SuccessMessage</c>. When this option is <c>true</c>, the calculated key for the property is
/// the property name e.g. <c>SuccessMessage</c>.
/// </para>
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
public bool SuppressTempDataAttributePrefix
{
get => _suppressTempDataAttributePrefix.Value;
set => _suppressTempDataAttributePrefix.Value = value;
}
/// <summary>
/// Gets or sets a value that indicates whether the maxlength attribute should be rendered for compatible HTML elements,
/// when they're bound to models marked with either
/// <see cref="StringLengthAttribute"/> or <see cref="MaxLengthAttribute"/> attributes.
/// </summary>
/// <value>
/// The default value is <see langword="true"/>.
/// </value>
/// <remarks>
/// If both attributes are specified, the one with the smaller value will be used for the rendered `maxlength` attribute.
/// </remarks>
public bool AllowRenderingMaxLengthAttribute
{
get => _allowRenderingMaxLengthAttribute.Value;
set => _allowRenderingMaxLengthAttribute.Value = value;
}
/// <summary>
/// Gets a list <see cref="IViewEngine"/>s used by this application.
/// </summary>
@ -100,10 +47,7 @@ namespace Microsoft.AspNetCore.Mvc
public IList<IClientModelValidatorProvider> ClientModelValidatorProviders { get; } =
new List<IClientModelValidatorProvider>();
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
{
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
}
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
}

View File

@ -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.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
{
internal class MvcViewOptionsConfigureCompatibilityOptions : ConfigureCompatibilityOptions<MvcViewOptions>
{
public MvcViewOptionsConfigureCompatibilityOptions(
ILoggerFactory loggerFactory,
IOptions<MvcCompatibilityOptions> compatibilityOptions)
: base(loggerFactory, compatibilityOptions)
{
}
protected override IReadOnlyDictionary<string, object> DefaultValues
{
get
{
return new Dictionary<string, object>
{
[nameof(MvcViewOptions.SuppressTempDataAttributePrefix)] = true,
[nameof(MvcViewOptions.AllowRenderingMaxLengthAttribute)] = true,
};
}
}
}
}

View File

@ -68,5 +68,15 @@
"TypeId": "public class Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor : Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor, Microsoft.AspNetCore.Mvc.Infrastructure.IActionResultExecutor<Microsoft.AspNetCore.Mvc.ViewResult>",
"MemberId": "public .ctor(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Mvc.MvcViewOptions> viewOptions, Microsoft.AspNetCore.Mvc.Infrastructure.IHttpResponseStreamWriterFactory writerFactory, Microsoft.AspNetCore.Mvc.ViewEngines.ICompositeViewEngine viewEngine, Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory tempDataFactory, System.Diagnostics.DiagnosticSource diagnosticSource, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider modelMetadataProvider)",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcViewOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Boolean get_SuppressTempDataAttributePrefix()",
"Kind": "Removal"
},
{
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcViewOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
"MemberId": "public System.Void set_SuppressTempDataAttributePrefix(System.Boolean value)",
"Kind": "Removal"
}
]
]

View File

@ -195,11 +195,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
// Throwing InputFormatterException
[Theory]
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
public async Task BindModel_CustomFormatter_ThrowingInputFormatterException_AddsErrorToModelState(
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
[Fact]
public async Task BindModel_CustomFormatter_ThrowingInputFormatterException_AddsErrorToModelState()
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -215,12 +212,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
throw new InputFormatterException("Bad input!!", expectedFormatException);
});
var binder = CreateBinder(
new[] { formatter },
new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -237,16 +229,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.Null(entry.Value.Errors[0].Exception);
}
public static TheoryData<IInputFormatter, InputFormatterExceptionPolicy> BuiltInFormattersThrowingInputFormatterException
public static TheoryData<IInputFormatter> BuiltInFormattersThrowingInputFormatterException
{
get
{
return new TheoryData<IInputFormatter, InputFormatterExceptionPolicy>()
return new TheoryData<IInputFormatter>()
{
{ new XmlSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.AllExceptions },
{ new XmlSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.AllExceptions },
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new XmlSerializerInputFormatter(new MvcOptions()) },
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()) },
};
}
}
@ -254,8 +244,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
[Theory]
[MemberData(nameof(BuiltInFormattersThrowingInputFormatterException))]
public async Task BindModel_BuiltInXmlInputFormatters_ThrowingInputFormatterException_AddsErrorToModelState(
IInputFormatter formatter,
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
IInputFormatter formatter)
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -266,10 +255,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -286,11 +272,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.Null(entry.Value.Errors[0].Exception);
}
[Theory]
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
public async Task BindModel_BuiltInJsonInputFormatter_ThrowingInputFormatterException_AddsErrorToModelState(
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
[Fact]
public async Task BindModel_BuiltInJsonInputFormatter_ThrowingInputFormatterException_AddsErrorToModelState()
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -303,10 +286,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(
new[] { new TestableJsonInputFormatter(throwNonInputFormatterException: false) },
new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -321,25 +301,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.NotEmpty(entry.Value.Errors[0].ErrorMessage);
}
public static TheoryData<IInputFormatter, InputFormatterExceptionPolicy> DerivedFormattersThrowingInputFormatterException
public static TheoryData<IInputFormatter> DerivedFormattersThrowingInputFormatterException
{
get
{
return new TheoryData<IInputFormatter, InputFormatterExceptionPolicy>()
return new TheoryData<IInputFormatter>()
{
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.AllExceptions },
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.AllExceptions },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false) },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false) },
};
}
}
[Theory]
[MemberData(nameof(DerivedFormattersThrowingInputFormatterException))]
public async Task BindModel_DerivedXmlInputFormatters_AddsErrorToModelState_(
IInputFormatter formatter,
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
public async Task BindModel_DerivedXmlInputFormatters_AddsErrorToModelState(IInputFormatter formatter)
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -350,10 +326,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -370,11 +343,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.Null(entry.Value.Errors[0].Exception);
}
[Theory]
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
public async Task BindModel_DerivedJsonInputFormatter_AddsErrorToModelState(
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
[Fact]
public async Task BindModel_DerivedJsonInputFormatter_AddsErrorToModelState()
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -387,10 +357,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(
new[] { new DerivedJsonInputFormatter(throwNonInputFormatterException: false) },
new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -407,18 +374,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
// Throwing Non-InputFormatterException
public static TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy> BuiltInFormattersThrowingNonInputFormatterException
public static TheoryData<IInputFormatter, string> BuiltInFormattersThrowingNonInputFormatterException
{
get
{
return new TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy>()
return new TheoryData<IInputFormatter, string>()
{
{ new TestableXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
{ new TestableXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.AllExceptions },
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new TestableXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json" },
};
}
}
@ -427,8 +391,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
[MemberData(nameof(BuiltInFormattersThrowingNonInputFormatterException))]
public async Task BindModel_BuiltInInputFormatters_ThrowingNonInputFormatterException_Throws(
IInputFormatter formatter,
string contentType,
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
string contentType)
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -439,28 +402,22 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act & Assert
var exception = await Assert.ThrowsAsync<IOException>(() => binder.BindModelAsync(bindingContext));
Assert.Equal("Unable to read input stream!!", exception.Message);
}
public static TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy> DerivedInputFormattersThrowingNonInputFormatterException
public static TheoryData<IInputFormatter, string> DerivedInputFormattersThrowingNonInputFormatterException
{
get
{
return new TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy>()
return new TheoryData<IInputFormatter, string>()
{
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.AllExceptions },
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.MalformedInputExceptions },
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json" },
};
}
}
@ -469,8 +426,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
[MemberData(nameof(DerivedInputFormattersThrowingNonInputFormatterException))]
public async Task BindModel_DerivedXmlInputFormatters_ThrowingNonInputFormattingException_AddsErrorToModelState(
IInputFormatter formatter,
string contentType,
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
string contentType)
{
// Arrange
var httpContext = new DefaultHttpContext();
@ -481,10 +437,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
{
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act
await binder.BindModelAsync(bindingContext);
@ -517,12 +470,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
throw new IOException("Unable to read input stream!!");
});
var binder = CreateBinder(
new[] { formatter },
new MvcOptions()
{
InputFormatterExceptionPolicy = InputFormatterExceptionPolicy.MalformedInputExceptions
});
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
// Act
var exception = await Assert.ThrowsAsync<IOException>(
@ -530,44 +478,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
Assert.Equal("Unable to read input stream!!", exception.Message);
}
[Fact]
public async Task BindModel_CustomFormatter_ThrowingNonInputFormatterException_AddsErrorToModelState()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("Bad data!"));
httpContext.Request.ContentType = "text/xyz";
var metadataProvider = new TestModelMetadataProvider();
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
var formatter = new XyzFormatter((inputFormatterContext, encoding) =>
{
throw new IOException("Unable to read input stream!!");
});
var binder = CreateBinder(
new[] { formatter },
new MvcOptions()
{
InputFormatterExceptionPolicy = InputFormatterExceptionPolicy.AllExceptions
});
// Act
await binder.BindModelAsync(bindingContext);
// Assert
Assert.False(bindingContext.Result.IsModelSet);
Assert.Null(bindingContext.Result.Model);
// Key is the empty string because this was a top-level binding.
var entry = Assert.Single(bindingContext.ModelState);
Assert.Equal(string.Empty, entry.Key);
var errorMessage = Assert.Single(entry.Value.Errors).Exception.Message;
Assert.Equal("Unable to read input stream!!", errorMessage);
Assert.IsType<IOException>(entry.Value.Errors[0].Exception);
}
[Fact]
public async Task NullFormatterError_AddedToModelState()
{

View File

@ -286,6 +286,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bool isBindingRequired)
{
// Arrange
var expectedErrorCount = isBindingRequired ? 1 : 0;
var mockValueProvider = new Mock<IValueProvider>();
mockValueProvider
.Setup(o => o.ContainsPrefix(It.IsAny<string>()))
@ -305,7 +306,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var bindingContext = new DefaultModelBindingContext
{
IsTopLevelObject = true,
ModelMetadata = GetMetadataForType(typeof(Person)),
ModelMetadata = metadata,
ModelName = string.Empty,
ValueProvider = mockValueProvider.Object,
ModelState = new ModelStateDictionary(),
@ -330,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Assert
Assert.True(bindingContext.Result.IsModelSet);
Assert.Equal(0, bindingContext.ModelState.ErrorCount);
Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
var returnedPerson = Assert.IsType<Person>(bindingContext.Result.Model);
Assert.Same(model, returnedPerson);
@ -1115,8 +1116,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var type = model.GetType();
var bindingContext = CreateContext(GetMetadataForType(type), model);
var modelState = bindingContext.ModelState;
var metadata = GetMetadataForType(type);
var propertyMetadata = bindingContext.ModelMetadata.Properties[propertyName];
var result = ModelBindingResult.Success(new Simple { Name = "Hanna" });
@ -1160,8 +1159,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var model = new Person();
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
var metadata = GetMetadataForType(typeof(Person));
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfBirth)];
var result = ModelBindingResult.Success(new DateTime(2001, 1, 1));
@ -1186,8 +1183,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
var metadata = GetMetadataForType(typeof(Person));
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfDeath)];
var result = ModelBindingResult.Success(new DateTime(1800, 1, 1));
@ -1210,8 +1205,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var model = new ModelWhosePropertySetterThrows();
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
bindingContext.ModelName = "foo";
var metadata = GetMetadataForType(typeof(ModelWhosePropertySetterThrows));
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.NameNoAttribute)];
var result = ModelBindingResult.Success(model: null);

View File

@ -12,21 +12,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public class EnumTypeModelBinderTest
{
[Theory]
[InlineData(true, typeof(IntEnum?))]
[InlineData(true, typeof(FlagsEnum?))]
[InlineData(false, typeof(IntEnum?))]
[InlineData(false, typeof(FlagsEnum?))]
public async Task BindModel_SetsModel_ForEmptyValue_AndNullableEnumTypes(
bool suppressBindingUndefinedValueToEnumType,
Type modelType)
[InlineData(typeof(IntEnum?))]
[InlineData(typeof(FlagsEnum?))]
public async Task BindModel_SetsModel_ForEmptyValue_AndNullableEnumTypes(Type modelType)
{
// Arrange
var binderInfo = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType,
valueProviderValue: "");
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
var (bindingContext, binder) = GetBinderAndContext(modelType, valueProviderValue: "");
// Act
await binder.BindModelAsync(bindingContext);
@ -37,22 +28,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Theory]
[InlineData(true, typeof(IntEnum))]
[InlineData(true, typeof(FlagsEnum))]
[InlineData(false, typeof(IntEnum))]
[InlineData(false, typeof(FlagsEnum))]
public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes(
bool suppressBindingUndefinedValueToEnumType,
Type modelType)
[InlineData(typeof(IntEnum))]
[InlineData(typeof(FlagsEnum))]
public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes(Type modelType)
{
// Arrange
var message = "The value '' is invalid.";
var binderInfo = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType,
valueProviderValue: "");
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
var (bindingContext, binder) = GetBinderAndContext(modelType, valueProviderValue: "");
// Act
await binder.BindModelAsync(bindingContext);
@ -66,22 +48,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Theory]
[InlineData(true, "Value1")]
[InlineData(true, "1")]
[InlineData(false, "Value1")]
[InlineData(false, "1")]
public async Task BindModel_BindsEnumModels_ForValuesInArray(
bool suppressBindingUndefinedValueToEnumType,
string enumValue)
[InlineData("Value1")]
[InlineData("1")]
public async Task BindModel_BindsEnumModels_ForValuesInArray(string enumValue)
{
// Arrange
var modelType = typeof(IntEnum);
var binderInfo = GetBinderAndContext(
var (bindingContext, binder) = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType,
valueProviderValue: new object[] { enumValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
@ -93,26 +68,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Theory]
[InlineData("1", true)]
[InlineData("8, 1", true)]
[InlineData("Value2, Value8", true)]
[InlineData("value8,value4,value2,value1", true)]
[InlineData("1", false)]
[InlineData("8, 1", false)]
[InlineData("Value2, Value8", false)]
[InlineData("value8,value4,value2,value1", false)]
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
[InlineData("1")]
[InlineData("8, 1")]
[InlineData("Value2, Value8")]
[InlineData("value8,value4,value2,value1")]
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue)
{
// Arrange
var modelType = typeof(FlagsEnum);
var enumConverter = TypeDescriptor.GetConverter(modelType);
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
var binderInfo = GetBinderAndContext(
var (bindingContext, binder) = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType,
valueProviderValue: new object[] { flagsEnumValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
@ -124,26 +92,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[Theory]
[InlineData("1", true)]
[InlineData("8, 1", true)]
[InlineData("Value2, Value8", true)]
[InlineData("value8,value4,value2,value1", true)]
[InlineData("1", false)]
[InlineData("8, 1", false)]
[InlineData("Value2, Value8", false)]
[InlineData("value8,value4,value2,value1", false)]
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
[InlineData("1")]
[InlineData("8, 1")]
[InlineData("Value2, Value8")]
[InlineData("value8,value4,value2,value1")]
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue)
{
// Arrange
var modelType = typeof(FlagsEnum?);
var enumConverter = TypeDescriptor.GetConverter(GetUnderlyingType(modelType));
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
var binderInfo = GetBinderAndContext(
var (bindingContext, binder) = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType,
valueProviderValue: new object[] { flagsEnumValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
@ -154,36 +115,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.Equal(expected, boundModel.ToString());
}
[Theory]
[InlineData(typeof(FlagsEnum), "Value10")]
[InlineData(typeof(FlagsEnum), "Value1, Value10")]
[InlineData(typeof(FlagsEnum), "value10, value1")]
[InlineData(typeof(FlagsEnum?), "Value10")]
[InlineData(typeof(FlagsEnum?), "Value1, Value10")]
[InlineData(typeof(FlagsEnum?), "value10, value1")]
public async Task BindModel_AddsErrorToModelState_ForInvalidEnumValues_IsNotValidMessage(Type modelType, string suppliedValue)
{
// Arrange
var message = $"The value '{suppliedValue}' is not valid.";
var binderInfo = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType: false,
valueProviderValue: new object[] { suppliedValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
// Assert
Assert.False(bindingContext.Result.IsModelSet);
Assert.Null(bindingContext.Result.Model);
Assert.False(bindingContext.ModelState.IsValid);
var error = Assert.Single(bindingContext.ModelState["theModelName"].Errors);
Assert.Equal(message, error.ErrorMessage);
}
[Theory]
[InlineData(typeof(IntEnum), "")]
[InlineData(typeof(IntEnum), "3")]
@ -206,12 +137,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
// Arrange
var message = $"The value '{suppliedValue}' is invalid.";
var binderInfo = GetBinderAndContext(
var (bindingContext, binder) = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType: true,
valueProviderValue: new object[] { suppliedValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
@ -224,49 +152,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.Equal(message, error.ErrorMessage);
}
[Theory]
[InlineData(typeof(IntEnum), "3", 3)]
[InlineData(typeof(FlagsEnum), "19", 19)]
[InlineData(typeof(FlagsEnum), "0", 0)]
[InlineData(typeof(FlagsEnum), "1, 16", 17)]
// These two values look like big integers but are treated as two separate enum values that are
// or'd together.
[InlineData(typeof(FlagsEnum), "32,015", 47)]
[InlineData(typeof(FlagsEnum), "32,128", 160)]
[InlineData(typeof(IntEnum?), "3", 3)]
[InlineData(typeof(FlagsEnum?), "19", 19)]
[InlineData(typeof(FlagsEnum?), "0", 0)]
[InlineData(typeof(FlagsEnum?), "1, 16", 17)]
// These two values look like big integers but are treated as two separate enum values that are
// or'd together.
[InlineData(typeof(FlagsEnum?), "32,015", 47)]
[InlineData(typeof(FlagsEnum?), "32,128", 160)]
public async Task BindModel_AllowsBindingUndefinedValues_ToEnumTypes(
Type modelType,
string suppliedValue,
long expected)
{
// Arrange
var binderProviderContext = new TestModelBinderProviderContext(modelType);
var binderInfo = GetBinderAndContext(
modelType,
suppressBindingUndefinedValueToEnumType: false,
valueProviderValue: new object[] { suppliedValue });
var bindingContext = binderInfo.Item1;
var binder = binderInfo.Item2;
// Act
await binder.BindModelAsync(bindingContext);
// Assert
Assert.True(bindingContext.Result.IsModelSet);
Assert.IsType(GetUnderlyingType(modelType), bindingContext.Result.Model);
Assert.Equal(expected, Convert.ToInt64(bindingContext.Result.Model));
}
private static (DefaultModelBindingContext, IModelBinder) GetBinderAndContext(
Type modelType,
bool suppressBindingUndefinedValueToEnumType,
object valueProviderValue)
{
var binderProviderContext = new TestModelBinderProviderContext(modelType);
@ -281,10 +168,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{ modelName, valueProviderValue }
}
};
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions
{
SuppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType
});
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions());
var binder = binderProvider.GetBinder(binderProviderContext);
return (bindingContext, binder);
}

View File

@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
{
public class DefaultObjectValidatorTests
{
private readonly MvcOptions _options = new MvcOptions { AllowShortCircuitingValidationWhenNoValidatorsArePresent = true };
private readonly MvcOptions _options = new MvcOptions();
private ModelMetadataProvider MetadataProvider { get; } = TestModelMetadataProvider.CreateDefaultProvider();

View File

@ -275,53 +275,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
Assert.Equal("DisplayNameAttributeValue", context.DisplayMetadata.DisplayName());
}
[Fact]
public void CreateDisplayMetadata_DisplayNameAttribute_OnEnum_CompatSwitchWorks()
{
// Arrange
var unsharedLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
unsharedLocalizer
.Setup(s => s["DisplayNameValue"])
.Returns(new LocalizedString("DisplaynameValue", "didn't use shared"));
var sharedLocalizer = new Mock<IStringLocalizer>(MockBehavior.Strict);
sharedLocalizer
.Setup(s => s["DisplayNameValue"])
.Returns(() => new LocalizedString("DisplayNameValue", "used shared"));
var stringLocalizerFactoryMock = new Mock<IStringLocalizerFactory>(MockBehavior.Strict);
stringLocalizerFactoryMock
.Setup(s => s.Create(typeof(TestEnum)))
.Returns(() => unsharedLocalizer.Object);
stringLocalizerFactoryMock
.Setup(s => s.Create(typeof(EmptyClass)))
.Returns(() => sharedLocalizer.Object);
var localizationOptions = Options.Create(new MvcDataAnnotationsLocalizationOptions());
localizationOptions.Value.AllowDataAnnotationsLocalizationForEnumDisplayAttributes = false;
localizationOptions.Value.DataAnnotationLocalizerProvider = (type, stringLocalizerFactory) =>
{
return stringLocalizerFactory.Create(typeof(EmptyClass));
};
var provider = new DataAnnotationsMetadataProvider(
localizationOptions,
stringLocalizerFactory: stringLocalizerFactoryMock.Object);
var displayName = new DisplayNameAttribute("DisplayNameValue");
var attributes = new Attribute[] { displayName };
var key = ModelMetadataIdentity.ForType(typeof(TestEnum));
var context = new DisplayMetadataProviderContext(key, GetModelAttributes(attributes));
// Act
provider.CreateDisplayMetadata(context);
// Assert
Assert.Collection(context.DisplayMetadata.EnumGroupedDisplayNamesAndValues,
(e) => Assert.Equal("didn't use shared", e.Key.Name));
}
[Fact]
public void CreateDisplayMetadata_DisplayNameAttribute_OnEnum_CompatShimOn()
{
@ -337,7 +290,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
.Returns(() => sharedLocalizer.Object);
var localizationOptions = Options.Create(new MvcDataAnnotationsLocalizationOptions());
localizationOptions.Value.AllowDataAnnotationsLocalizationForEnumDisplayAttributes = true;
localizationOptions.Value.DataAnnotationLocalizerProvider = (type, stringLocalizerFactory) =>
{
return stringLocalizerFactory.Create(typeof(EmptyClass));
@ -1269,7 +1221,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
new RequiredAttribute(),
new StringLengthAttribute(5)
};
Assert.Equal(expected, actual: context.ValidationMetadata.ValidatorMetadata);
}
@ -1580,7 +1532,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
private class FooCompositeValidationAttribute : ValidationProviderAttribute
{
private IEnumerable<ValidationAttribute> _attributes;
private readonly IEnumerable<ValidationAttribute> _attributes;
public FooCompositeValidationAttribute(IEnumerable<ValidationAttribute> attributes)
{

View File

@ -725,35 +725,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
treatEmptyInputAsDefaultValue: treatEmptyInputAsDefaultValue);
}
private IEnumerable<string> GetModelStateErrorMessages(ModelStateDictionary modelStateDictionary)
{
var allErrorMessages = new List<string>();
foreach (var keyModelStatePair in modelStateDictionary)
{
var key = keyModelStatePair.Key;
var errors = keyModelStatePair.Value.Errors;
if (errors != null && errors.Count > 0)
{
foreach (var modelError in errors)
{
if (string.IsNullOrEmpty(modelError.ErrorMessage))
{
if (modelError.Exception != null)
{
allErrorMessages.Add(modelError.Exception.Message);
}
}
else
{
allErrorMessages.Add(modelError.ErrorMessage);
}
}
}
}
return allErrorMessages;
}
private sealed class User
{
public string Name { get; set; }

View File

@ -3,7 +3,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
@ -15,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsFormatterMapping()
{
// Arrange
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act
@ -30,7 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void DoesNotOverrideExistingMapping()
{
// Arrange
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
@ -46,7 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsInputFormatter()
{
// Arrange
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act
@ -60,7 +59,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsOutputFormatter()
{
// Arrange
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act

View File

@ -3,8 +3,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
@ -16,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsFormatterMapping()
{
// Arrange
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act
@ -31,7 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void DoesNotOverrideExistingMapping()
{
// Arrange
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
@ -47,7 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsInputFormatter()
{
// Arrange
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act
@ -61,7 +59,7 @@ namespace Microsoft.Extensions.DependencyInjection
public void AddsOutputFormatter()
{
// Arrange
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
var options = new MvcOptions();
// Act

View File

@ -11,8 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
public void GetProvider_ReturnsNull_IfTypeDoesNotMatch()
{
// Arrange
var xmlOptions = new MvcXmlOptions();
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var providerFactory = new ProblemDetailsWrapperProviderFactory();
var context = new WrapperProviderContext(typeof(SerializableError), isSerialization: true);
// Act
@ -26,8 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
public void GetProvider_ReturnsWrapper_ForProblemDetails()
{
// Arrange
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var providerFactory = new ProblemDetailsWrapperProviderFactory();
var instance = new ProblemDetails();
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
@ -40,32 +38,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
Assert.Same(instance, wrapper.ProblemDetails);
}
[Fact]
public void GetProvider_Returns21CompatibleWrapper_ForProblemDetails()
{
// Arrange
var xmlOptions = new MvcXmlOptions();
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var instance = new ProblemDetails();
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
// Act
var provider = providerFactory.GetProvider(context);
// Assert
var result = provider.Wrap(instance);
#pragma warning disable CS0618 // Type or member is obsolete
var wrapper = Assert.IsType<ProblemDetails21Wrapper>(result);
#pragma warning restore CS0618 // Type or member is obsolete
Assert.Same(instance, wrapper.ProblemDetails);
}
[Fact]
public void GetProvider_ReturnsWrapper_ForValidationProblemDetails()
{
// Arrange
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var providerFactory = new ProblemDetailsWrapperProviderFactory();
var instance = new ValidationProblemDetails();
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
@ -78,32 +55,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
Assert.Same(instance, wrapper.ProblemDetails);
}
[Fact]
public void GetProvider_Returns21CompatibleWrapper_ForValidationProblemDetails()
{
// Arrange
var xmlOptions = new MvcXmlOptions();
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var instance = new ValidationProblemDetails();
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
// Act
var provider = providerFactory.GetProvider(context);
// Assert
var result = provider.Wrap(instance);
#pragma warning disable CS0618 // Type or member is obsolete
var wrapper = Assert.IsType<ValidationProblemDetails21Wrapper>(result);
#pragma warning restore CS0618 // Type or member is obsolete
Assert.Same(instance, wrapper.ProblemDetails);
}
[Fact]
public void GetProvider_ReturnsNull_ForCustomProblemDetails()
{
// Arrange
var xmlOptions = new MvcXmlOptions();
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
var providerFactory = new ProblemDetailsWrapperProviderFactory();
var instance = new CustomProblemDetails();
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);

View File

@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
return new DefaultObjectValidator(
metadataProvider,
GetModelValidatorProviders(options),
options?.Value ?? new MvcOptions { AllowShortCircuitingValidationWhenNoValidatorsArePresent = true });
options?.Value ?? new MvcOptions());
}
private static IList<IModelValidatorProvider> GetModelValidatorProviders(IOptions<MvcOptions> options)
@ -195,8 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
serviceCollection
.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>()
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>()
.Configure<MvcOptions>(options => options.AllowShortCircuitingValidationWhenNoValidatorsArePresent = true);
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>();
if (updateOptions != null)
{

View File

@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
Options.Create(new RazorPagesOptions()));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);

View File

@ -137,7 +137,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
var options = new RazorPagesOptions
{
AllowAreas = true,
// Setting this value should not affect area page lookup.
RootDirectory = "/Files",
};
@ -213,44 +212,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
});
}
[Fact]
public void OnProvidersExecuting_DoesNotAddsModelsForAreaPages_IfFeatureIsDisabled()
{
// Arrange
var descriptors = new[]
{
CreateVersion_2_0_Descriptor("/Pages/About.cshtml"),
CreateVersion_2_0_Descriptor("/Areas/Accounts/Pages/Home.cshtml"),
};
var options = new RazorPagesOptions { AllowAreas = false };
var provider = CreateProvider(options: options, descriptors: descriptors);
var context = new PageRouteModelProviderContext();
// Act
provider.OnProvidersExecuting(context);
// Assert
Assert.Collection(
context.RouteModels,
result =>
{
Assert.Equal("/Pages/About.cshtml", result.RelativePath);
Assert.Equal("/About", result.ViewEnginePath);
Assert.Collection(
result.Selectors,
selector => Assert.Equal("About", selector.AttributeRouteModel.Template));
Assert.Collection(
result.RouteValues.OrderBy(k => k.Key),
kvp =>
{
Assert.Equal("page", kvp.Key);
Assert.Equal("/About", kvp.Value);
});
});
}
[Fact]
public void OnProvidersExecuting_DoesNotAddAreaAndNonAreaRoutesForAPage()
{
@ -265,7 +226,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
var options = new RazorPagesOptions
{
AllowAreas = true,
RootDirectory = "/",
};
@ -637,4 +597,4 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
}
}
}
}
}

View File

@ -1036,24 +1036,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
public void OnGetUser() { }
}
[Fact]
public void PopulateFilters_With21CompatBehavior_DoesNotAddDisallowOptionsRequestsPageFilter()
{
// Arrange
var provider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new RazorPagesOptions()));
var typeInfo = typeof(object).GetTypeInfo();
var pageModel = new PageApplicationModel(new PageActionDescriptor(), typeInfo, typeInfo.GetCustomAttributes(inherit: true));
// Act
provider.PopulateFilters(pageModel);
// Assert
Assert.Empty(pageModel.Filters);
}
[Fact]
public void PopulateFilters_AddsDisallowOptionsRequestsPageFilter()
{
@ -1189,7 +1171,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
{
return new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
Options.Create(new RazorPagesOptions()));
}
}
}

View File

@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters
{
var defaultProvider = new DefaultPageApplicationModelProvider(
TestModelMetadataProvider.CreateDefaultProvider(),
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
Options.Create(new RazorPagesOptions()));
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
defaultProvider.OnProvidersExecuting(context);

View File

@ -80,17 +80,17 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
filter.Properties,
property =>
{
Assert.Equal("TempDataProperty-Test2", property.Key);
Assert.Equal("Test2", property.Key);
Assert.Equal(type.GetProperty(nameof(TestPageModel_OneTempDataProperty.Test2)), property.PropertyInfo);
});
}
[Fact]
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString_IfCompatSwitchIsSet()
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString()
{
// Arrange
var type = typeof(TestPageModel_OneTempDataProperty);
var options = Options.Create(new MvcViewOptions { SuppressTempDataAttributePrefix = true });
var options = Options.Create(new MvcViewOptions());
var provider = new TempDataFilterPageApplicationModelProvider(options);
var context = CreateProviderContext(type);

View File

@ -6,55 +6,12 @@ using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Options;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
public class DefaultPageHandlerMethodSelectorTest
{
[Fact]
public void LegacyBehavior_Select_ReturnsNull_WhenNoHandlerMatchesHttpMethod()
{
// Arrange
var descriptor1 = new HandlerMethodDescriptor
{
HttpMethod = "GET"
};
var descriptor2 = new HandlerMethodDescriptor
{
HttpMethod = "POST"
};
var pageContext = new PageContext
{
ActionDescriptor = new CompiledPageActionDescriptor
{
HandlerMethods = new List<HandlerMethodDescriptor>()
{
descriptor1,
descriptor2,
},
},
RouteData = new RouteData(),
HttpContext = new DefaultHttpContext
{
Request =
{
Method = "PUT"
},
},
};
var selector = CreateSelector(legacyBehavior: true);
// Act
var actual = selector.Select(pageContext);
// Assert
Assert.Null(actual);
}
[Fact]
public void NewBehavior_Select_ReturnsFuzzyMatchForHead_WhenNoHeadHandlerDefined()
{
@ -780,13 +737,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
{
}
private static DefaultPageHandlerMethodSelector CreateSelector(bool legacyBehavior = false)
private static DefaultPageHandlerMethodSelector CreateSelector()
{
var options = Options.Create(new RazorPagesOptions()
{
AllowMappingHeadRequestsToGetHandler = !legacyBehavior
});
return new DefaultPageHandlerMethodSelector(options);
return new DefaultPageHandlerMethodSelector();
}
}
}

View File

@ -1,92 +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.Hosting;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.IntegrationTest
{
// Integration tests for compatibility switches. These tests verify which compatibility
// values apply to each supported version.
//
// If you add a new compatibility switch, make sure to update ALL of these tests. Each test
// here should include verification for all of the switches.
public class CompatibilitySwitchIntegrationTest
{
[Fact]
public void CompatibilitySwitches_Version_3_0()
{
// Arrange
var serviceCollection = new ServiceCollection();
AddHostingServices(serviceCollection);
serviceCollection
.AddMvc()
.AddXmlDataContractSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
var services = serviceCollection.BuildServiceProvider();
// Act
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
var jsonOptions = services.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
// Assert
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
Assert.True(razorPagesOptions.AllowAreas);
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
}
[Fact]
public void CompatibilitySwitches_Version_Latest()
{
// Arrange
var serviceCollection = new ServiceCollection();
AddHostingServices(serviceCollection);
serviceCollection
.AddMvc()
.AddXmlDataContractSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Latest);
var services = serviceCollection.BuildServiceProvider();
// Act
var mvcOptions = services.GetRequiredService<IOptions<MvcOptions>>().Value;
var jsonOptions = services.GetRequiredService<IOptions<MvcJsonOptions>>().Value;
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
// Assert
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
Assert.True(razorPagesOptions.AllowAreas);
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
Assert.True(mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent);
}
// This just does the minimum needed to be able to resolve these options.
private static void AddHostingServices(IServiceCollection serviceCollection)
{
serviceCollection.AddSingleton(Mock.Of<IHostingEnvironment>());
serviceCollection.AddLogging();
serviceCollection.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
}
}
}

View File

@ -20,7 +20,6 @@ using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewComponents;
@ -382,13 +381,6 @@ namespace Microsoft.AspNetCore.Mvc
typeof(MvcCoreMvcOptionsSetup),
}
},
{
typeof(IPostConfigureOptions<RazorPagesOptions>),
new[]
{
typeof(RazorPagesOptionsConfigureCompatibilityOptions),
}
},
{
typeof(IActionConstraintProvider),
new Type[]

View File

@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Assert
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
Assert.Equal(expectedValue, Int32.Parse(attribute.Value));
Assert.Equal(expectedValue, int.Parse(attribute.Value));
}
[Theory]
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Assert
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
Assert.Equal(expectedValue, Int32.Parse(attribute.Value));
Assert.Equal(expectedValue, int.Parse(attribute.Value));
}
[Theory]
@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Assert
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
Assert.Equal(expectedValue, Int32.Parse(attribute.Value));
Assert.Equal(expectedValue, int.Parse(attribute.Value));
}
[Fact]
@ -282,7 +282,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Assert
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
Assert.Equal(Math.Min(ModelWithMaxLengthMetadata.MaxLengthAttributeValue, ModelWithMaxLengthMetadata.StringLengthAttributeValue), Int32.Parse(attribute.Value));
Assert.Equal(Math.Min(ModelWithMaxLengthMetadata.MaxLengthAttributeValue, ModelWithMaxLengthMetadata.StringLengthAttributeValue), int.Parse(attribute.Value));
}
[Fact]
@ -328,7 +328,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
// Assert
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
Assert.Equal(expectedValue, Int32.Parse(attribute.Value));
Assert.Equal(expectedValue, int.Parse(attribute.Value));
}
[Theory]
@ -923,7 +923,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
private static IHtmlGenerator GetGenerator(IModelMetadataProvider metadataProvider)
{
var mvcViewOptionsAccessor = new Mock<IOptions<MvcViewOptions>>();
mvcViewOptionsAccessor.SetupGet(accessor => accessor.Value).Returns(new MvcViewOptions() { AllowRenderingMaxLengthAttribute = true });
mvcViewOptionsAccessor.SetupGet(accessor => accessor.Value).Returns(new MvcViewOptions());
var htmlEncoder = Mock.Of<HtmlEncoder>();
var antiforgery = new Mock<IAntiforgery>();

View File

@ -85,15 +85,15 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
Assert.NotNull(filter);
var property = Assert.Single(filter.TempDataProperties);
Assert.Same(expected, property.PropertyInfo);
Assert.Equal("TempDataProperty-Test2", property.Key);
Assert.Equal("Test2", property.Key);
}
[Fact]
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString_IfCompatSwitchIsSet()
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString()
{
// Arrange
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2));
var options = Options.Create(new MvcViewOptions { SuppressTempDataAttributePrefix = true });
var options = Options.Create(new MvcViewOptions());
var type = typeof(TestController_OneTempDataProperty);
var provider = new TempDataApplicationModelProvider(options);
var context = GetContext(type);

View File

@ -27,7 +27,6 @@ namespace RazorPagesWebSite
.AddCookieTempDataProvider()
.AddRazorPagesOptions(options =>
{
options.AllowAreas = true;
options.Conventions.AuthorizePage("/Conventions/Auth");
options.Conventions.AuthorizeFolder("/Conventions/AuthFolder");
options.Conventions.AuthorizeAreaFolder("Accounts", "/RequiresAuth");