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:
parent
db0c347c23
commit
f113a20dfd
|
|
@ -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;
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -192,7 +192,6 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
var additionalParts = GetAdditionalParts();
|
var additionalParts = GetAdditionalParts();
|
||||||
var mvcBuilder = services
|
var mvcBuilder = services
|
||||||
.AddMvc()
|
.AddMvc()
|
||||||
.AddRazorPagesOptions(o => o.AllowAreas = true)
|
|
||||||
.ConfigureApplicationPartManager(apm =>
|
.ConfigureApplicationPartManager(apm =>
|
||||||
{
|
{
|
||||||
foreach (var part in additionalParts)
|
foreach (var part in additionalParts)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -193,7 +193,6 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
var additionalParts = GetAdditionalParts();
|
var additionalParts = GetAdditionalParts();
|
||||||
var mvcBuilder = services
|
var mvcBuilder = services
|
||||||
.AddMvc()
|
.AddMvc()
|
||||||
.AddRazorPagesOptions(o => o.AllowAreas = true)
|
|
||||||
.ConfigureApplicationPartManager(apm =>
|
.ConfigureApplicationPartManager(apm =>
|
||||||
{
|
{
|
||||||
foreach (var part in additionalParts)
|
foreach (var part in additionalParts)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -37,7 +37,6 @@ namespace Microsoft.AspNetCore.Identity.UI
|
||||||
name = name ?? throw new ArgumentNullException(nameof(name));
|
name = name ?? throw new ArgumentNullException(nameof(name));
|
||||||
options = options ?? throw new ArgumentNullException(nameof(options));
|
options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
options.AllowAreas = true;
|
|
||||||
options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");
|
options.Conventions.AuthorizeAreaFolder(IdentityUIDefaultAreaName, "/Account/Manage");
|
||||||
options.Conventions.AuthorizeAreaPage(IdentityUIDefaultAreaName, "/Account/Logout");
|
options.Conventions.AuthorizeAreaPage(IdentityUIDefaultAreaName, "/Account/Logout");
|
||||||
var convention = new IdentityPageModelConvention<TUser>();
|
var convention = new IdentityPageModelConvention<TUser>();
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the set of policies that determine how the model binding system interprets exceptions
|
/// Defines the set of policies that determine how the model binding system interprets exceptions
|
||||||
/// thrown by an <see cref="IInputFormatter"/>. Applications should set
|
/// thrown by an <see cref="IInputFormatter"/>. <seealso cref="IInputFormatterExceptionPolicy"/>
|
||||||
/// <c>MvcOptions.InputFormatterExceptionPolicy</c> to configure this setting.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
|
|
@ -25,12 +24,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// The policy associated with <see cref="InputFormatterExceptionPolicy.AllExceptions"/> treats
|
/// 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
|
/// 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
|
/// 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>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// The policy associated with <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>
|
/// The policy associated with <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>
|
||||||
/// treats only <see cref="InputFormatterException"/> and its subclasses as model state errors. This means that
|
/// 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.
|
/// which by default would cause an HTTP 500 response, unless there is exception-handling middleware enabled.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
|
|
@ -44,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This value indicates that only <see cref="InputFormatterException"/> and subclasses will be treated
|
/// 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.
|
/// level exception handler, such as exception-handling middleware.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MalformedInputExceptions = 1,
|
MalformedInputExceptions = 1,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
/// constraints.</param>
|
/// constraints.</param>
|
||||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||||
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
||||||
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
|
/// <remarks>The <paramref name="mapper"/> parameter is currently ignored.</remarks>
|
||||||
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
|
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
|
||||||
public DefaultApiDescriptionProvider(
|
public DefaultApiDescriptionProvider(
|
||||||
IOptions<MvcOptions> optionsAccessor,
|
IOptions<MvcOptions> optionsAccessor,
|
||||||
|
|
@ -76,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
|
||||||
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
|
||||||
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
/// <param name="mapper">The <see cref="IActionResultTypeMapper"/>.</param>
|
||||||
/// <param name="routeOptions">The accessor for <see cref="RouteOptions"/>.</param>
|
/// <param name="routeOptions">The accessor for <see cref="RouteOptions"/>.</param>
|
||||||
/// <remarks>The <paramref name="mapper"/> parameter is currently unused.</remarks>
|
/// <remarks>The <paramref name="mapper"/> parameter is currently ignored.</remarks>
|
||||||
public DefaultApiDescriptionProvider(
|
public DefaultApiDescriptionProvider(
|
||||||
IOptions<MvcOptions> optionsAccessor,
|
IOptions<MvcOptions> optionsAccessor,
|
||||||
IInlineConstraintResolver constraintResolver,
|
IInlineConstraintResolver constraintResolver,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ApiBehaviorOptions : IEnumerable<ICompatibilitySwitch>
|
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;
|
private Func<ActionContext, IActionResult> _invalidModelStateResponseFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -84,10 +84,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } = new Dictionary<int, ClientErrorData>();
|
public IDictionary<int, ClientErrorData> ClientErrorMapping { get; } = new Dictionary<int, ClientErrorData>();
|
||||||
|
|
||||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
{
|
|
||||||
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,14 +52,8 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// ASP.NET Core MVC 2.1.
|
/// ASP.NET Core MVC 2.1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// ASP.NET Core MVC 2.1 introduced compatibility switches for the following:
|
/// ASP.NET Core MVC 2.1 introduced a compatibility switch for
|
||||||
/// <list type="bullet">
|
/// <c>MvcJsonOptions.AllowInputFormatterExceptionMessages</c>. This is now a regular property.
|
||||||
/// <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>
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
|
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
|
||||||
nameof(Version_3_0) + " or later.")]
|
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:
|
/// ASP.NET Core MVC 2.2 introduced compatibility switches for the following:
|
||||||
/// <list type="bullet">
|
/// <list type="bullet">
|
||||||
/// <item><description><c>ApiBehaviorOptions.SuppressMapClientErrors</c></description></item>
|
/// <item><description><c>ApiBehaviorOptions.SuppressMapClientErrors</c></description></item>
|
||||||
/// <item><description><c>MvcDataAnnotationsLocalizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes</c></description></item>
|
|
||||||
/// <item><description><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
|
/// <item><description><see cref="MvcOptions.EnableEndpointRouting" /></description></item>
|
||||||
/// <item><description><see cref="MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent"/></description></item>
|
|
||||||
/// <item><description><see cref="MvcOptions.MaxValidationDepth" /></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>
|
/// </list>
|
||||||
|
/// All of the above are now regular properties.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
|
[Obsolete("This " + nameof(CompatibilityVersion) + " value is obsolete. The recommended alternatives are " +
|
||||||
nameof(Version_3_0) + " or later.")]
|
nameof(Version_3_0) + " or later.")]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|
@ -21,12 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new Dictionary<string, object>
|
return new Dictionary<string, object>();
|
||||||
{
|
|
||||||
[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions,
|
|
||||||
[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true,
|
|
||||||
[nameof(MvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent)] = true,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,13 +192,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
private bool ShouldHandleException(IInputFormatter formatter)
|
private bool ShouldHandleException(IInputFormatter formatter)
|
||||||
{
|
{
|
||||||
var policy = _options.InputFormatterExceptionPolicy;
|
// Any explicit policy on the formatters overrides the default.
|
||||||
|
var policy = (formatter as IInputFormatterExceptionPolicy)?.ExceptionPolicy ??
|
||||||
// Any explicit policy on the formatters takes precedence over the global policy on MvcOptions
|
InputFormatterExceptionPolicy.MalformedInputExceptions;
|
||||||
if (formatter is IInputFormatterExceptionPolicy exceptionPolicy)
|
|
||||||
{
|
|
||||||
policy = exceptionPolicy.ExceptionPolicy;
|
|
||||||
}
|
|
||||||
|
|
||||||
return policy == InputFormatterExceptionPolicy.AllExceptions;
|
return policy == InputFormatterExceptionPolicy.AllExceptions;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EnumTypeModelBinder : SimpleTypeModelBinder
|
public class EnumTypeModelBinder : SimpleTypeModelBinder
|
||||||
{
|
{
|
||||||
private readonly bool _suppressBindingUndefinedValueToEnumType;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="EnumTypeModelBinder"/>.
|
/// Initializes a new instance of <see cref="EnumTypeModelBinder"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -22,6 +20,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="modelType">The model type.</param>
|
/// <param name="modelType">The model type.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>,</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>,</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <paramref name="suppressBindingUndefinedValueToEnumType"/> parameter is currently ignored.
|
||||||
|
/// </remarks>
|
||||||
public EnumTypeModelBinder(
|
public EnumTypeModelBinder(
|
||||||
bool suppressBindingUndefinedValueToEnumType,
|
bool suppressBindingUndefinedValueToEnumType,
|
||||||
Type modelType,
|
Type modelType,
|
||||||
|
|
@ -37,8 +38,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(loggerFactory));
|
throw new ArgumentNullException(nameof(loggerFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
_suppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckModel(
|
protected override void CheckModel(
|
||||||
|
|
@ -46,23 +45,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
ValueProviderResult valueProviderResult,
|
ValueProviderResult valueProviderResult,
|
||||||
object model)
|
object model)
|
||||||
{
|
{
|
||||||
if (model == null || !_suppressBindingUndefinedValueToEnumType)
|
if (model == null)
|
||||||
{
|
{
|
||||||
base.CheckModel(bindingContext, valueProviderResult, model);
|
base.CheckModel(bindingContext, valueProviderResult, model);
|
||||||
}
|
}
|
||||||
|
else if (IsDefinedInEnum(model, bindingContext))
|
||||||
|
{
|
||||||
|
bindingContext.Result = ModelBindingResult.Success(model);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IsDefinedInEnum(model, bindingContext))
|
bindingContext.ModelState.TryAddModelError(
|
||||||
{
|
bindingContext.ModelName,
|
||||||
bindingContext.Result = ModelBindingResult.Success(model);
|
bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(
|
||||||
}
|
valueProviderResult.ToString()));
|
||||||
else
|
|
||||||
{
|
|
||||||
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;
|
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.
|
// converts value to the backing type (ex: integer) and does not check if the value is defined on the enum.
|
||||||
if (bindingContext.ModelMetadata.IsFlagsEnum)
|
if (bindingContext.ModelMetadata.IsFlagsEnum)
|
||||||
{
|
{
|
||||||
// Enum.IsDefined does not work with combined flag enum values.
|
// Enum.IsDefined does not work with combined flag enum values.
|
||||||
// From EnumDataTypeAttribute.cs in CoreFX.
|
// From EnumDataTypeAttribute.cs in CoreFX.
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
// [Flags]
|
// [Flags]
|
||||||
// enum FlagsEnum { Value1 = 1, Value2 = 2, Value4 = 4 }
|
// enum FlagsEnum { Value1 = 1, Value2 = 2, Value4 = 4 }
|
||||||
//
|
//
|
||||||
|
|
@ -87,7 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
//
|
//
|
||||||
// Invalid Scenarios:
|
// Invalid Scenarios:
|
||||||
// 1. valueProviderResult="2,10", model=12, underlying=12, converted=12
|
// 1. valueProviderResult="2,10", model=12, underlying=12, converted=12
|
||||||
//
|
//
|
||||||
var underlying = Convert.ChangeType(
|
var underlying = Convert.ChangeType(
|
||||||
model,
|
model,
|
||||||
Enum.GetUnderlyingType(modelType),
|
Enum.GetUnderlyingType(modelType),
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EnumTypeModelBinderProvider : IModelBinderProvider
|
public class EnumTypeModelBinderProvider : IModelBinderProvider
|
||||||
{
|
{
|
||||||
private readonly MvcOptions _options;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="EnumTypeModelBinderProvider"/>.
|
/// Initializes a new instance of <see cref="EnumTypeModelBinderProvider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
/// <param name="options">The <see cref="MvcOptions"/>.</param>
|
||||||
|
/// <remarks>The <paramref name="options"/> parameter is currently ignored.</remarks>
|
||||||
public EnumTypeModelBinderProvider(MvcOptions options)
|
public EnumTypeModelBinderProvider(MvcOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -35,7 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
|
||||||
return new EnumTypeModelBinder(
|
return new EnumTypeModelBinder(
|
||||||
_options.SuppressBindingUndefinedValueToEnumType,
|
suppressBindingUndefinedValueToEnumType: true,
|
||||||
context.Metadata.UnderlyingOrModelType,
|
context.Metadata.UnderlyingOrModelType,
|
||||||
loggerFactory);
|
loggerFactory);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
|
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
|
||||||
/// <param name="mvcOptions">The <see cref="MvcOptions"/> accessor.</param>
|
/// <param name="mvcOptions">The <see cref="MvcOptions"/> accessor.</param>
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
/// <remarks>The <paramref name="mvcOptions"/> parameter is currently unused.</remarks>
|
/// <remarks>The <paramref name="mvcOptions"/> parameter is currently ignored.</remarks>
|
||||||
public ParameterBinder(
|
public ParameterBinder(
|
||||||
IModelMetadataProvider modelMetadataProvider,
|
IModelMetadataProvider modelMetadataProvider,
|
||||||
IModelBinderFactory modelBinderFactory,
|
IModelBinderFactory modelBinderFactory,
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
validationState)
|
validationState)
|
||||||
{
|
{
|
||||||
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
|
MaxValidationDepth = _mvcOptions.MaxValidationDepth,
|
||||||
AllowShortCircuitingValidationWhenNoValidatorsArePresent =
|
|
||||||
_mvcOptions.AllowShortCircuitingValidationWhenNoValidatorsArePresent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return visitor;
|
return visitor;
|
||||||
|
|
|
||||||
|
|
@ -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
|
/// Gets or sets a value that determines if <see cref="ValidationVisitor"/> can short circuit validation when a model
|
||||||
/// does not have any associated validators.
|
/// does not have any associated validators.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Validates a object.
|
/// 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
|
// 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.
|
// is not invalid (i.e. is one of Unvalidated, Valid, or Skipped) we can safely mark the graph as valid.
|
||||||
else if (
|
else if (metadata.HasValidators == false &&
|
||||||
AllowShortCircuitingValidationWhenNoValidatorsArePresent &&
|
|
||||||
metadata.HasValidators == false &&
|
|
||||||
ModelState.GetFieldValidationState(key) != ModelValidationState.Invalid)
|
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.
|
// No validators will be created for this graph of objects. Mark it as valid if it wasn't previously validated.
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
// See CompatibilitySwitch.cs for guide on how to implement these.
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
|
|
||||||
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowShortCircuitingValidationWhenNoValidatorsArePresent;
|
|
||||||
|
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||||
private int? _maxValidationDepth = 32;
|
private int? _maxValidationDepth = 32;
|
||||||
|
|
||||||
|
|
@ -44,17 +39,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
|
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
|
||||||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||||
ValueProviderFactories = new List<IValueProviderFactory>();
|
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>
|
/// <summary>
|
||||||
|
|
@ -102,36 +86,11 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FormatterMappings FormatterMappings { get; }
|
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>
|
/// <summary>
|
||||||
/// Gets a list of <see cref="IInputFormatter"/>s that are used by this application.
|
/// Gets a list of <see cref="IInputFormatter"/>s that are used by this application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FormatterCollection<IInputFormatter> InputFormatters { get; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the flag to buffer the request body in input formatters. Default is <c>false</c>.
|
/// Gets or sets the flag to buffer the request body in input formatters. Default is <c>false</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -250,30 +209,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
/// 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 IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,5 +102,25 @@
|
||||||
"TypeId": "public class Microsoft.AspNetCore.Mvc.MvcOptions : System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Mvc.Infrastructure.ICompatibilitySwitch>",
|
"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)",
|
"MemberId": "public System.Void set_AllowValidatingTopLevelNodes(System.Boolean value)",
|
||||||
"Kind": "Removal"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
<IConfigureOptions<MvcDataAnnotationsLocalizationOptions>,
|
<IConfigureOptions<MvcDataAnnotationsLocalizationOptions>,
|
||||||
MvcDataAnnotationsLocalizationOptionsSetup>());
|
MvcDataAnnotationsLocalizationOptionsSetup>());
|
||||||
}
|
}
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcDataAnnotationsLocalizationOptions>, MvcDataAnnotationsLocalizationConfigureCompatibilityOptions>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -184,16 +184,9 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
var namesAndValues = new Dictionary<string, string>();
|
var namesAndValues = new Dictionary<string, string>();
|
||||||
|
|
||||||
IStringLocalizer enumLocalizer = null;
|
IStringLocalizer enumLocalizer = null;
|
||||||
if (_localizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes)
|
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
|
||||||
{
|
{
|
||||||
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
|
enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory);
|
||||||
{
|
|
||||||
enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enumLocalizer = _stringLocalizerFactory?.Create(underlyingType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var enumFields = Enum.GetNames(underlyingType)
|
var enumFields = Enum.GetNames(underlyingType)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,42 +14,14 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcDataAnnotationsLocalizationOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcDataAnnotationsLocalizationOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _allowDataAnnotationsLocalizationForEnumDisplayAttributes;
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The delegate to invoke for creating <see cref="IStringLocalizer"/>.
|
/// The delegate to invoke for creating <see cref="IStringLocalizer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<Type, IStringLocalizerFactory, IStringLocalizer> DataAnnotationLocalizerProvider;
|
public Func<Type, IStringLocalizerFactory, IStringLocalizer> DataAnnotationLocalizerProvider;
|
||||||
|
|
||||||
/// <summary>
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
/// 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 IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
|
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJsonPatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override InputFormatterExceptionPolicy ExceptionPolicy
|
public override InputFormatterExceptionPolicy ExceptionPolicy
|
||||||
{
|
{
|
||||||
|
|
@ -180,4 +180,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
return base.CanRead(context);
|
return base.CanRead(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcJsonOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly ICompatibilitySwitch[] _switches = Array.Empty<ICompatibilitySwitch>();
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a flag to determine whether error messages from JSON deserialization by the
|
/// Gets or sets a flag to determine whether error messages from JSON deserialization by the
|
||||||
|
|
@ -38,10 +38,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JsonSerializerSettings SerializerSettings { get; } = JsonSerializerSettingsProvider.CreateSerializerSettings();
|
public JsonSerializerSettings SerializerSettings { get; } = JsonSerializerSettingsProvider.CreateSerializerSettings();
|
||||||
|
|
||||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
{
|
|
||||||
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing.
|
// Internal for testing.
|
||||||
|
|
@ -129,9 +126,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,9 +120,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal for testing.
|
// Internal for testing.
|
||||||
|
|
@ -130,9 +127,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,19 +18,14 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class XmlDataContractSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
internal sealed class XmlDataContractSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||||
{
|
{
|
||||||
private readonly MvcXmlOptions _xmlOptions;
|
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="XmlDataContractSerializerMvcOptionsSetup"/>.
|
/// Initializes a new instance of <see cref="XmlDataContractSerializerMvcOptionsSetup"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
|
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
public XmlDataContractSerializerMvcOptionsSetup(
|
public XmlDataContractSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
|
||||||
IOptions<MvcXmlOptions> xmlOptions,
|
|
||||||
ILoggerFactory loggerFactory)
|
|
||||||
{
|
{
|
||||||
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
|
|
||||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,11 +38,11 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
options.ModelMetadataDetailsProviders.Add(new DataMemberRequiredBindingMetadataProvider());
|
options.ModelMetadataDetailsProviders.Add(new DataMemberRequiredBindingMetadataProvider());
|
||||||
|
|
||||||
var inputFormatter = new XmlDataContractSerializerInputFormatter(options);
|
var inputFormatter = new XmlDataContractSerializerInputFormatter(options);
|
||||||
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
|
||||||
options.InputFormatters.Add(inputFormatter);
|
options.InputFormatters.Add(inputFormatter);
|
||||||
|
|
||||||
var outputFormatter = new XmlDataContractSerializerOutputFormatter(_loggerFactory);
|
var outputFormatter = new XmlDataContractSerializerOutputFormatter(_loggerFactory);
|
||||||
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
|
||||||
options.OutputFormatters.Add(outputFormatter);
|
options.OutputFormatters.Add(outputFormatter);
|
||||||
|
|
||||||
// Do not override any user mapping
|
// Do not override any user mapping
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,14 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class XmlSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
internal sealed class XmlSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||||
{
|
{
|
||||||
private readonly MvcXmlOptions _xmlOptions;
|
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="XmlSerializerMvcOptionsSetup"/>.
|
/// Initializes a new instance of <see cref="XmlSerializerMvcOptionsSetup"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
|
|
||||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
public XmlSerializerMvcOptionsSetup(
|
public XmlSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
|
||||||
IOptions<MvcXmlOptions> xmlOptions,
|
|
||||||
ILoggerFactory loggerFactory)
|
|
||||||
{
|
{
|
||||||
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
|
|
||||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,11 +44,11 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
}
|
}
|
||||||
|
|
||||||
var inputFormatter = new XmlSerializerInputFormatter(options);
|
var inputFormatter = new XmlSerializerInputFormatter(options);
|
||||||
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
|
||||||
options.InputFormatters.Add(inputFormatter);
|
options.InputFormatters.Add(inputFormatter);
|
||||||
|
|
||||||
var outputFormatter = new XmlSerializerOutputFormatter(_loggerFactory);
|
var outputFormatter = new XmlSerializerOutputFormatter(_loggerFactory);
|
||||||
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory());
|
||||||
options.OutputFormatters.Add(outputFormatter);
|
options.OutputFormatters.Add(outputFormatter);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
|
|
@ -10,39 +11,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides configuration for XML formatters.
|
/// Provides configuration for XML formatters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This class is currently empty.</remarks>
|
||||||
public class MvcXmlOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcXmlOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _allowRfc7807CompliantProblemDetailsFormat;
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly IReadOnlyList<ICompatibilitySwitch> _switches;
|
|
||||||
|
|
||||||
/// <summary>
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
/// Creates a new instance of <see cref="MvcXmlOptions"/>.
|
|
||||||
/// </summary>
|
|
||||||
public MvcXmlOptions()
|
|
||||||
{
|
|
||||||
_allowRfc7807CompliantProblemDetailsFormat = new CompatibilitySwitch<bool>(nameof(AllowRfc7807CompliantProblemDetailsFormat));
|
|
||||||
|
|
||||||
_switches = new ICompatibilitySwitch[]
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
{
|
|
||||||
_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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,41 +7,16 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
{
|
{
|
||||||
internal class ProblemDetailsWrapperProviderFactory : IWrapperProviderFactory
|
internal class ProblemDetailsWrapperProviderFactory : IWrapperProviderFactory
|
||||||
{
|
{
|
||||||
private readonly MvcXmlOptions _options;
|
|
||||||
|
|
||||||
public ProblemDetailsWrapperProviderFactory(MvcXmlOptions options)
|
|
||||||
{
|
|
||||||
_options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IWrapperProvider GetProvider(WrapperProviderContext context)
|
public IWrapperProvider GetProvider(WrapperProviderContext context)
|
||||||
{
|
{
|
||||||
if (context.DeclaredType == typeof(ProblemDetails))
|
if (context.DeclaredType == typeof(ProblemDetails))
|
||||||
{
|
{
|
||||||
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
|
return new WrapperProvider(typeof(ProblemDetailsWrapper), p => new ProblemDetailsWrapper((ProblemDetails)p));
|
||||||
{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.DeclaredType == typeof(ValidationProblemDetails))
|
if (context.DeclaredType == typeof(ValidationProblemDetails))
|
||||||
{
|
{
|
||||||
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
|
return new WrapperProvider(typeof(ValidationProblemDetailsWrapper), p => new ValidationProblemDetailsWrapper((ValidationProblemDetails)p));
|
||||||
{
|
|
||||||
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 null;
|
return null;
|
||||||
|
|
@ -62,4 +37,4 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
public object Wrap(object original) => WrapDelegate(original);
|
public object Wrap(object original) => WrapDelegate(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
|
||||||
// When RootDirectory and AreaRootDirectory overlap (e.g. RootDirectory = '/', AreaRootDirectory = '/Areas'), we
|
// When RootDirectory and AreaRootDirectory overlap (e.g. RootDirectory = '/', AreaRootDirectory = '/Areas'), we
|
||||||
// only want to allow a page to be associated with the area route.
|
// 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);
|
routeModel = _routeModelFactory.CreateAreaRouteModel(relativePath, routeTemplate);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,10 +179,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
pageModel.Filters.Add(_pageHandlerResultFilter);
|
pageModel.Filters.Add(_pageHandlerResultFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_razorPagesOptions.AllowDefaultHandlingForOptionsRequests)
|
pageModel.Filters.Add(_handleOptionsRequestsFilter);
|
||||||
{
|
|
||||||
pageModel.Filters.Add(_handleOptionsRequestsFilter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
|
|
@ -82,8 +81,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
// Options
|
// Options
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorPagesRazorViewEngineOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorPagesRazorViewEngineOptionsSetup>());
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<RazorPagesOptions>, RazorPagesOptionsConfigureCompatibilityOptions>());
|
|
||||||
|
|
||||||
// Action description and invocation
|
// Action description and invocation
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -13,20 +12,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
private const string Handler = "handler";
|
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)
|
public HandlerMethodDescriptor Select(PageContext context)
|
||||||
{
|
{
|
||||||
var handlers = SelectHandlers(context);
|
var handlers = SelectHandlers(context);
|
||||||
|
|
@ -113,7 +98,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1a: do fuzzy HTTP method matching if needed.
|
// Step 1a: do fuzzy HTTP method matching if needed.
|
||||||
if (candidates.Count == 0 && AllowFuzzyHttpMethodMatching)
|
if (candidates.Count == 0)
|
||||||
{
|
{
|
||||||
var fuzzyHttpMethod = GetFuzzyMatchHttpMethod(context);
|
var fuzzyHttpMethod = GetFuzzyMatchHttpMethod(context);
|
||||||
if (fuzzyHttpMethod != null)
|
if (fuzzyHttpMethod != null)
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RazorPagesOptions : IEnumerable<ICompatibilitySwitch>
|
public class RazorPagesOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _allowAreas;
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly CompatibilitySwitch<bool> _allowMappingHeadRequestsToGetHandler;
|
|
||||||
private readonly CompatibilitySwitch<bool> _allowsDefaultHandlingForOptionsRequests;
|
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
|
|
||||||
private string _root = "/Pages";
|
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>
|
/// <summary>
|
||||||
/// Gets a collection of <see cref="IPageConvention"/> instances that are applied during
|
/// Gets a collection of <see cref="IPageConvention"/> instances that are applied during
|
||||||
/// route and page model construction.
|
/// route and page model construction.
|
||||||
|
|
@ -64,70 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
/// 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 IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -27,5 +27,25 @@
|
||||||
{
|
{
|
||||||
"TypeId": "public static class Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageDirectiveFeature",
|
"TypeId": "public static class Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageDirectiveFeature",
|
||||||
"Kind": "Removal"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -95,17 +95,24 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Underscores are fine characters in id's.
|
// Underscores are fine characters in id's.
|
||||||
IdAttributeDotReplacement = optionsAccessor.Value.HtmlHelperOptions.IdAttributeDotReplacement;
|
IdAttributeDotReplacement = optionsAccessor.Value.HtmlHelperOptions.IdAttributeDotReplacement;
|
||||||
|
|
||||||
AllowRenderingMaxLengthAttribute = optionsAccessor.Value.AllowRenderingMaxLengthAttribute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value that indicates whether the maxlength attribute should be rendered for compatible HTML input elements,
|
/// Gets or sets a value that indicates whether the <c>maxlength</c> attribute should be rendered for
|
||||||
/// when they're bound to models marked with either
|
/// compatible HTML input elements, when they're bound to models marked with either
|
||||||
/// <see cref="StringLengthAttribute"/> or <see cref="MaxLengthAttribute"/> attributes.
|
/// <see cref="StringLengthAttribute"/> or <see cref="MaxLengthAttribute"/> attributes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>If both attributes are specified, the one with the smaller value will be used for the rendered `maxlength` attribute.</remarks>
|
/// <value>The default value is <see langword="true"/>.</value>
|
||||||
protected bool AllowRenderingMaxLengthAttribute { get; }
|
/// <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 />
|
/// <inheritdoc />
|
||||||
public string IdAttributeDotReplacement { get; }
|
public string IdAttributeDotReplacement { get; }
|
||||||
|
|
@ -737,11 +744,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
}
|
}
|
||||||
|
|
||||||
AddPlaceholderAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
|
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);
|
AddValidationAttributes(viewContext, tagBuilder, modelExplorer, expression);
|
||||||
|
|
||||||
// If there are any errors for a named field, we add this CSS attribute.
|
// 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);
|
AddPlaceholderAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AllowRenderingMaxLengthAttribute && _maxLengthInputTypes.Contains(suppliedTypeString))
|
if (_maxLengthInputTypes.Contains(suppliedTypeString))
|
||||||
{
|
{
|
||||||
AddMaxLengthAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
|
AddMaxLengthAttribute(viewContext.ViewData, tagBuilder, modelExplorer, expression);
|
||||||
}
|
}
|
||||||
|
|
@ -1397,7 +1400,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a maxlength attribute to the <paramref name="tagBuilder" />.
|
/// Adds a <c>maxlength</c> attribute to the <paramref name="tagBuilder" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="viewData">A <see cref="ViewDataDictionary"/> instance for the current scope.</param>
|
/// <param name="viewData">A <see cref="ViewDataDictionary"/> instance for the current scope.</param>
|
||||||
/// <param name="tagBuilder">A <see cref="TagBuilder"/> instance.</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.
|
// Second check the Eval() call returned a collection of SelectListItems.
|
||||||
var selectList = value as IEnumerable<SelectListItem>;
|
if (!(value is IEnumerable<SelectListItem> selectList))
|
||||||
if (selectList == null)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatHtmlHelper_WrongSelectDataType(
|
throw new InvalidOperationException(Resources.FormatHtmlHelper_WrongSelectDataType(
|
||||||
expression,
|
expression,
|
||||||
|
|
@ -1606,8 +1608,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
IEnumerable<SelectListItem> selectList,
|
IEnumerable<SelectListItem> selectList,
|
||||||
ICollection<string> currentValues)
|
ICollection<string> currentValues)
|
||||||
{
|
{
|
||||||
var itemsList = selectList as IList<SelectListItem>;
|
if (!(selectList is IList<SelectListItem> itemsList))
|
||||||
if (itemsList == null)
|
|
||||||
{
|
{
|
||||||
itemsList = selectList.ToList();
|
itemsList = selectList.ToList();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,6 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcViewOptionsSetup>());
|
||||||
services.TryAddEnumerable(
|
|
||||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcViewOptions>, MvcViewOptionsConfigureCompatibilityOptions>());
|
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());
|
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, TempDataMvcOptionsSetup>());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,6 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
|
||||||
List<LifecycleProperty> results = null;
|
List<LifecycleProperty> results = null;
|
||||||
|
|
||||||
var propertyHelpers = PropertyHelper.GetVisibleProperties(type: type);
|
var propertyHelpers = PropertyHelper.GetVisibleProperties(type: type);
|
||||||
var prefix = viewOptions.SuppressTempDataAttributePrefix ?
|
|
||||||
string.Empty :
|
|
||||||
"TempDataProperty-";
|
|
||||||
|
|
||||||
for (var i = 0; i < propertyHelpers.Length; i++)
|
for (var i = 0; i < propertyHelpers.Length; i++)
|
||||||
{
|
{
|
||||||
var propertyHelper = propertyHelpers[i];
|
var propertyHelper = propertyHelpers[i];
|
||||||
|
|
@ -105,7 +101,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
|
||||||
var key = tempDataAttribute.Key;
|
var key = tempDataAttribute.Key;
|
||||||
if (string.IsNullOrEmpty(key))
|
if (string.IsNullOrEmpty(key))
|
||||||
{
|
{
|
||||||
key = prefix + property.Name;
|
key = property.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.Add(new LifecycleProperty(property, key));
|
results.Add(new LifecycleProperty(property, key));
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||||
|
|
@ -17,22 +16,9 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MvcViewOptions : IEnumerable<ICompatibilitySwitch>
|
public class MvcViewOptions : IEnumerable<ICompatibilitySwitch>
|
||||||
{
|
{
|
||||||
private readonly CompatibilitySwitch<bool> _suppressTempDataAttributePrefix;
|
private readonly IReadOnlyList<ICompatibilitySwitch> _switches = Array.Empty<ICompatibilitySwitch>();
|
||||||
private readonly CompatibilitySwitch<bool> _allowRenderingMaxLengthAttribute;
|
|
||||||
private readonly ICompatibilitySwitch[] _switches;
|
|
||||||
private HtmlHelperOptions _htmlHelperOptions = new HtmlHelperOptions();
|
private HtmlHelperOptions _htmlHelperOptions = new HtmlHelperOptions();
|
||||||
|
|
||||||
public MvcViewOptions()
|
|
||||||
{
|
|
||||||
_suppressTempDataAttributePrefix = new CompatibilitySwitch<bool>(nameof(SuppressTempDataAttributePrefix));
|
|
||||||
_allowRenderingMaxLengthAttribute = new CompatibilitySwitch<bool>(nameof(AllowRenderingMaxLengthAttribute));
|
|
||||||
_switches = new[]
|
|
||||||
{
|
|
||||||
_suppressTempDataAttributePrefix,
|
|
||||||
_allowRenderingMaxLengthAttribute
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets programmatic configuration for the HTML helpers and <see cref="Rendering.ViewContext"/>.
|
/// Gets or sets programmatic configuration for the HTML helpers and <see cref="Rendering.ViewContext"/>.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Gets a list <see cref="IViewEngine"/>s used by this application.
|
/// Gets a list <see cref="IViewEngine"/>s used by this application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -100,10 +47,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
public IList<IClientModelValidatorProvider> ClientModelValidatorProviders { get; } =
|
public IList<IClientModelValidatorProvider> ClientModelValidatorProviders { get; } =
|
||||||
new List<IClientModelValidatorProvider>();
|
new List<IClientModelValidatorProvider>();
|
||||||
|
|
||||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator() => _switches.GetEnumerator();
|
||||||
{
|
|
||||||
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => _switches.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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>",
|
"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)",
|
"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"
|
"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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -195,11 +195,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throwing InputFormatterException
|
// Throwing InputFormatterException
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
|
public async Task BindModel_CustomFormatter_ThrowingInputFormatterException_AddsErrorToModelState()
|
||||||
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
|
|
||||||
public async Task BindModel_CustomFormatter_ThrowingInputFormatterException_AddsErrorToModelState(
|
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -215,12 +212,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
throw new InputFormatterException("Bad input!!", expectedFormatException);
|
throw new InputFormatterException("Bad input!!", expectedFormatException);
|
||||||
});
|
});
|
||||||
var binder = CreateBinder(
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
new[] { formatter },
|
|
||||||
new MvcOptions()
|
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -237,16 +229,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.Null(entry.Value.Errors[0].Exception);
|
Assert.Null(entry.Value.Errors[0].Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<IInputFormatter, InputFormatterExceptionPolicy> BuiltInFormattersThrowingInputFormatterException
|
public static TheoryData<IInputFormatter> BuiltInFormattersThrowingInputFormatterException
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TheoryData<IInputFormatter, InputFormatterExceptionPolicy>()
|
return new TheoryData<IInputFormatter>()
|
||||||
{
|
{
|
||||||
{ new XmlSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.AllExceptions },
|
{ new XmlSerializerInputFormatter(new MvcOptions()) },
|
||||||
{ new XmlSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.MalformedInputExceptions },
|
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()) },
|
||||||
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.AllExceptions },
|
|
||||||
{ new XmlDataContractSerializerInputFormatter(new MvcOptions()), InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,8 +244,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(BuiltInFormattersThrowingInputFormatterException))]
|
[MemberData(nameof(BuiltInFormattersThrowingInputFormatterException))]
|
||||||
public async Task BindModel_BuiltInXmlInputFormatters_ThrowingInputFormatterException_AddsErrorToModelState(
|
public async Task BindModel_BuiltInXmlInputFormatters_ThrowingInputFormatterException_AddsErrorToModelState(
|
||||||
IInputFormatter formatter,
|
IInputFormatter formatter)
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -266,10 +255,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
||||||
|
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -286,11 +272,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.Null(entry.Value.Errors[0].Exception);
|
Assert.Null(entry.Value.Errors[0].Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
|
public async Task BindModel_BuiltInJsonInputFormatter_ThrowingInputFormatterException_AddsErrorToModelState()
|
||||||
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
|
|
||||||
public async Task BindModel_BuiltInJsonInputFormatter_ThrowingInputFormatterException_AddsErrorToModelState(
|
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -303,10 +286,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(
|
var binder = CreateBinder(
|
||||||
new[] { new TestableJsonInputFormatter(throwNonInputFormatterException: false) },
|
new[] { new TestableJsonInputFormatter(throwNonInputFormatterException: false) },
|
||||||
new MvcOptions()
|
new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -321,25 +301,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.NotEmpty(entry.Value.Errors[0].ErrorMessage);
|
Assert.NotEmpty(entry.Value.Errors[0].ErrorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<IInputFormatter, InputFormatterExceptionPolicy> DerivedFormattersThrowingInputFormatterException
|
public static TheoryData<IInputFormatter> DerivedFormattersThrowingInputFormatterException
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return new TheoryData<IInputFormatter, InputFormatterExceptionPolicy>()
|
return new TheoryData<IInputFormatter>()
|
||||||
{
|
{
|
||||||
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.AllExceptions },
|
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false) },
|
||||||
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.MalformedInputExceptions },
|
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false) },
|
||||||
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.AllExceptions },
|
|
||||||
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: false), InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(DerivedFormattersThrowingInputFormatterException))]
|
[MemberData(nameof(DerivedFormattersThrowingInputFormatterException))]
|
||||||
public async Task BindModel_DerivedXmlInputFormatters_AddsErrorToModelState_(
|
public async Task BindModel_DerivedXmlInputFormatters_AddsErrorToModelState(IInputFormatter formatter)
|
||||||
IInputFormatter formatter,
|
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -350,10 +326,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
||||||
|
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -370,11 +343,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
Assert.Null(entry.Value.Errors[0].Exception);
|
Assert.Null(entry.Value.Errors[0].Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(InputFormatterExceptionPolicy.AllExceptions)]
|
public async Task BindModel_DerivedJsonInputFormatter_AddsErrorToModelState()
|
||||||
[InlineData(InputFormatterExceptionPolicy.MalformedInputExceptions)]
|
|
||||||
public async Task BindModel_DerivedJsonInputFormatter_AddsErrorToModelState(
|
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -387,10 +357,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(
|
var binder = CreateBinder(
|
||||||
new[] { new DerivedJsonInputFormatter(throwNonInputFormatterException: false) },
|
new[] { new DerivedJsonInputFormatter(throwNonInputFormatterException: false) },
|
||||||
new MvcOptions()
|
new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -407,18 +374,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throwing Non-InputFormatterException
|
// Throwing Non-InputFormatterException
|
||||||
public static TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy> BuiltInFormattersThrowingNonInputFormatterException
|
public static TheoryData<IInputFormatter, string> BuiltInFormattersThrowingNonInputFormatterException
|
||||||
{
|
{
|
||||||
get
|
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" },
|
||||||
{ new TestableXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
|
||||||
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
|
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json" },
|
||||||
{ new TestableXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.AllExceptions },
|
|
||||||
{ new TestableJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -427,8 +391,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
[MemberData(nameof(BuiltInFormattersThrowingNonInputFormatterException))]
|
[MemberData(nameof(BuiltInFormattersThrowingNonInputFormatterException))]
|
||||||
public async Task BindModel_BuiltInInputFormatters_ThrowingNonInputFormatterException_Throws(
|
public async Task BindModel_BuiltInInputFormatters_ThrowingNonInputFormatterException_Throws(
|
||||||
IInputFormatter formatter,
|
IInputFormatter formatter,
|
||||||
string contentType,
|
string contentType)
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -439,28 +402,22 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
||||||
|
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var exception = await Assert.ThrowsAsync<IOException>(() => binder.BindModelAsync(bindingContext));
|
var exception = await Assert.ThrowsAsync<IOException>(() => binder.BindModelAsync(bindingContext));
|
||||||
Assert.Equal("Unable to read input stream!!", exception.Message);
|
Assert.Equal("Unable to read input stream!!", exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TheoryData<IInputFormatter, string, InputFormatterExceptionPolicy> DerivedInputFormattersThrowingNonInputFormatterException
|
public static TheoryData<IInputFormatter, string> DerivedInputFormattersThrowingNonInputFormatterException
|
||||||
{
|
{
|
||||||
get
|
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" },
|
||||||
{ new DerivedXmlSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml" },
|
||||||
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.AllExceptions },
|
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json" },
|
||||||
{ new DerivedXmlDataContractSerializerInputFormatter(throwNonInputFormatterException: true), "text/xml", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.AllExceptions },
|
|
||||||
{ new DerivedJsonInputFormatter(throwNonInputFormatterException: true), "text/json", InputFormatterExceptionPolicy.MalformedInputExceptions },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -469,8 +426,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
[MemberData(nameof(DerivedInputFormattersThrowingNonInputFormatterException))]
|
[MemberData(nameof(DerivedInputFormattersThrowingNonInputFormatterException))]
|
||||||
public async Task BindModel_DerivedXmlInputFormatters_ThrowingNonInputFormattingException_AddsErrorToModelState(
|
public async Task BindModel_DerivedXmlInputFormatters_ThrowingNonInputFormattingException_AddsErrorToModelState(
|
||||||
IInputFormatter formatter,
|
IInputFormatter formatter,
|
||||||
string contentType,
|
string contentType)
|
||||||
InputFormatterExceptionPolicy inputFormatterExceptionPolicy)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
@ -481,10 +437,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
metadataProvider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
|
||||||
|
|
||||||
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
var bindingContext = GetBindingContext(typeof(Person), httpContext, metadataProvider);
|
||||||
var binder = CreateBinder(new[] { formatter }, new MvcOptions()
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = inputFormatterExceptionPolicy
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -517,12 +470,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
{
|
{
|
||||||
throw new IOException("Unable to read input stream!!");
|
throw new IOException("Unable to read input stream!!");
|
||||||
});
|
});
|
||||||
var binder = CreateBinder(
|
var binder = CreateBinder(new[] { formatter }, new MvcOptions());
|
||||||
new[] { formatter },
|
|
||||||
new MvcOptions()
|
|
||||||
{
|
|
||||||
InputFormatterExceptionPolicy = InputFormatterExceptionPolicy.MalformedInputExceptions
|
|
||||||
});
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var exception = await Assert.ThrowsAsync<IOException>(
|
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);
|
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]
|
[Fact]
|
||||||
public async Task NullFormatterError_AddedToModelState()
|
public async Task NullFormatterError_AddedToModelState()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -286,6 +286,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
bool isBindingRequired)
|
bool isBindingRequired)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var expectedErrorCount = isBindingRequired ? 1 : 0;
|
||||||
var mockValueProvider = new Mock<IValueProvider>();
|
var mockValueProvider = new Mock<IValueProvider>();
|
||||||
mockValueProvider
|
mockValueProvider
|
||||||
.Setup(o => o.ContainsPrefix(It.IsAny<string>()))
|
.Setup(o => o.ContainsPrefix(It.IsAny<string>()))
|
||||||
|
|
@ -305,7 +306,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var bindingContext = new DefaultModelBindingContext
|
var bindingContext = new DefaultModelBindingContext
|
||||||
{
|
{
|
||||||
IsTopLevelObject = true,
|
IsTopLevelObject = true,
|
||||||
ModelMetadata = GetMetadataForType(typeof(Person)),
|
ModelMetadata = metadata,
|
||||||
ModelName = string.Empty,
|
ModelName = string.Empty,
|
||||||
ValueProvider = mockValueProvider.Object,
|
ValueProvider = mockValueProvider.Object,
|
||||||
ModelState = new ModelStateDictionary(),
|
ModelState = new ModelStateDictionary(),
|
||||||
|
|
@ -330,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(bindingContext.Result.IsModelSet);
|
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);
|
var returnedPerson = Assert.IsType<Person>(bindingContext.Result.Model);
|
||||||
Assert.Same(model, returnedPerson);
|
Assert.Same(model, returnedPerson);
|
||||||
|
|
@ -1115,8 +1116,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var type = model.GetType();
|
var type = model.GetType();
|
||||||
var bindingContext = CreateContext(GetMetadataForType(type), model);
|
var bindingContext = CreateContext(GetMetadataForType(type), model);
|
||||||
var modelState = bindingContext.ModelState;
|
var modelState = bindingContext.ModelState;
|
||||||
var metadata = GetMetadataForType(type);
|
|
||||||
|
|
||||||
var propertyMetadata = bindingContext.ModelMetadata.Properties[propertyName];
|
var propertyMetadata = bindingContext.ModelMetadata.Properties[propertyName];
|
||||||
var result = ModelBindingResult.Success(new Simple { Name = "Hanna" });
|
var result = ModelBindingResult.Success(new Simple { Name = "Hanna" });
|
||||||
|
|
||||||
|
|
@ -1160,8 +1159,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
// Arrange
|
// Arrange
|
||||||
var model = new Person();
|
var model = new Person();
|
||||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||||
|
|
||||||
var metadata = GetMetadataForType(typeof(Person));
|
|
||||||
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfBirth)];
|
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfBirth)];
|
||||||
|
|
||||||
var result = ModelBindingResult.Success(new DateTime(2001, 1, 1));
|
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 bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||||
|
|
||||||
var metadata = GetMetadataForType(typeof(Person));
|
|
||||||
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfDeath)];
|
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.DateOfDeath)];
|
||||||
|
|
||||||
var result = ModelBindingResult.Success(new DateTime(1800, 1, 1));
|
var result = ModelBindingResult.Success(new DateTime(1800, 1, 1));
|
||||||
|
|
@ -1210,8 +1205,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
||||||
var model = new ModelWhosePropertySetterThrows();
|
var model = new ModelWhosePropertySetterThrows();
|
||||||
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
var bindingContext = CreateContext(GetMetadataForType(model.GetType()), model);
|
||||||
bindingContext.ModelName = "foo";
|
bindingContext.ModelName = "foo";
|
||||||
|
|
||||||
var metadata = GetMetadataForType(typeof(ModelWhosePropertySetterThrows));
|
|
||||||
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.NameNoAttribute)];
|
var propertyMetadata = bindingContext.ModelMetadata.Properties[nameof(model.NameNoAttribute)];
|
||||||
|
|
||||||
var result = ModelBindingResult.Success(model: null);
|
var result = ModelBindingResult.Success(model: null);
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
public class EnumTypeModelBinderTest
|
public class EnumTypeModelBinderTest
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true, typeof(IntEnum?))]
|
[InlineData(typeof(IntEnum?))]
|
||||||
[InlineData(true, typeof(FlagsEnum?))]
|
[InlineData(typeof(FlagsEnum?))]
|
||||||
[InlineData(false, typeof(IntEnum?))]
|
public async Task BindModel_SetsModel_ForEmptyValue_AndNullableEnumTypes(Type modelType)
|
||||||
[InlineData(false, typeof(FlagsEnum?))]
|
|
||||||
public async Task BindModel_SetsModel_ForEmptyValue_AndNullableEnumTypes(
|
|
||||||
bool suppressBindingUndefinedValueToEnumType,
|
|
||||||
Type modelType)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(modelType, valueProviderValue: "");
|
||||||
modelType,
|
|
||||||
suppressBindingUndefinedValueToEnumType,
|
|
||||||
valueProviderValue: "");
|
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -37,22 +28,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true, typeof(IntEnum))]
|
[InlineData(typeof(IntEnum))]
|
||||||
[InlineData(true, typeof(FlagsEnum))]
|
[InlineData(typeof(FlagsEnum))]
|
||||||
[InlineData(false, typeof(IntEnum))]
|
public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes(Type modelType)
|
||||||
[InlineData(false, typeof(FlagsEnum))]
|
|
||||||
public async Task BindModel_AddsErrorToModelState_ForEmptyValue_AndNonNullableEnumTypes(
|
|
||||||
bool suppressBindingUndefinedValueToEnumType,
|
|
||||||
Type modelType)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var message = "The value '' is invalid.";
|
var message = "The value '' is invalid.";
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(modelType, valueProviderValue: "");
|
||||||
modelType,
|
|
||||||
suppressBindingUndefinedValueToEnumType,
|
|
||||||
valueProviderValue: "");
|
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -66,22 +48,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(true, "Value1")]
|
[InlineData("Value1")]
|
||||||
[InlineData(true, "1")]
|
[InlineData("1")]
|
||||||
[InlineData(false, "Value1")]
|
public async Task BindModel_BindsEnumModels_ForValuesInArray(string enumValue)
|
||||||
[InlineData(false, "1")]
|
|
||||||
public async Task BindModel_BindsEnumModels_ForValuesInArray(
|
|
||||||
bool suppressBindingUndefinedValueToEnumType,
|
|
||||||
string enumValue)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var modelType = typeof(IntEnum);
|
var modelType = typeof(IntEnum);
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(
|
||||||
modelType,
|
modelType,
|
||||||
suppressBindingUndefinedValueToEnumType,
|
|
||||||
valueProviderValue: new object[] { enumValue });
|
valueProviderValue: new object[] { enumValue });
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -93,26 +68,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("1", true)]
|
[InlineData("1")]
|
||||||
[InlineData("8, 1", true)]
|
[InlineData("8, 1")]
|
||||||
[InlineData("Value2, Value8", true)]
|
[InlineData("Value2, Value8")]
|
||||||
[InlineData("value8,value4,value2,value1", true)]
|
[InlineData("value8,value4,value2,value1")]
|
||||||
[InlineData("1", false)]
|
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue)
|
||||||
[InlineData("8, 1", false)]
|
|
||||||
[InlineData("Value2, Value8", false)]
|
|
||||||
[InlineData("value8,value4,value2,value1", false)]
|
|
||||||
public async Task BindModel_BindsTo_NonNullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var modelType = typeof(FlagsEnum);
|
var modelType = typeof(FlagsEnum);
|
||||||
var enumConverter = TypeDescriptor.GetConverter(modelType);
|
var enumConverter = TypeDescriptor.GetConverter(modelType);
|
||||||
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(
|
||||||
modelType,
|
modelType,
|
||||||
suppressBindingUndefinedValueToEnumType,
|
|
||||||
valueProviderValue: new object[] { flagsEnumValue });
|
valueProviderValue: new object[] { flagsEnumValue });
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -124,26 +92,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("1", true)]
|
[InlineData("1")]
|
||||||
[InlineData("8, 1", true)]
|
[InlineData("8, 1")]
|
||||||
[InlineData("Value2, Value8", true)]
|
[InlineData("Value2, Value8")]
|
||||||
[InlineData("value8,value4,value2,value1", true)]
|
[InlineData("value8,value4,value2,value1")]
|
||||||
[InlineData("1", false)]
|
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue)
|
||||||
[InlineData("8, 1", false)]
|
|
||||||
[InlineData("Value2, Value8", false)]
|
|
||||||
[InlineData("value8,value4,value2,value1", false)]
|
|
||||||
public async Task BindModel_BindsTo_NullableFlagsEnumType(string flagsEnumValue, bool suppressBindingUndefinedValueToEnumType)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var modelType = typeof(FlagsEnum?);
|
var modelType = typeof(FlagsEnum?);
|
||||||
var enumConverter = TypeDescriptor.GetConverter(GetUnderlyingType(modelType));
|
var enumConverter = TypeDescriptor.GetConverter(GetUnderlyingType(modelType));
|
||||||
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
var expected = enumConverter.ConvertFrom(flagsEnumValue).ToString();
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(
|
||||||
modelType,
|
modelType,
|
||||||
suppressBindingUndefinedValueToEnumType,
|
|
||||||
valueProviderValue: new object[] { flagsEnumValue });
|
valueProviderValue: new object[] { flagsEnumValue });
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -154,36 +115,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
Assert.Equal(expected, boundModel.ToString());
|
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]
|
[Theory]
|
||||||
[InlineData(typeof(IntEnum), "")]
|
[InlineData(typeof(IntEnum), "")]
|
||||||
[InlineData(typeof(IntEnum), "3")]
|
[InlineData(typeof(IntEnum), "3")]
|
||||||
|
|
@ -206,12 +137,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var message = $"The value '{suppliedValue}' is invalid.";
|
var message = $"The value '{suppliedValue}' is invalid.";
|
||||||
var binderInfo = GetBinderAndContext(
|
var (bindingContext, binder) = GetBinderAndContext(
|
||||||
modelType,
|
modelType,
|
||||||
suppressBindingUndefinedValueToEnumType: true,
|
|
||||||
valueProviderValue: new object[] { suppliedValue });
|
valueProviderValue: new object[] { suppliedValue });
|
||||||
var bindingContext = binderInfo.Item1;
|
|
||||||
var binder = binderInfo.Item2;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await binder.BindModelAsync(bindingContext);
|
await binder.BindModelAsync(bindingContext);
|
||||||
|
|
@ -224,49 +152,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
Assert.Equal(message, error.ErrorMessage);
|
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(
|
private static (DefaultModelBindingContext, IModelBinder) GetBinderAndContext(
|
||||||
Type modelType,
|
Type modelType,
|
||||||
bool suppressBindingUndefinedValueToEnumType,
|
|
||||||
object valueProviderValue)
|
object valueProviderValue)
|
||||||
{
|
{
|
||||||
var binderProviderContext = new TestModelBinderProviderContext(modelType);
|
var binderProviderContext = new TestModelBinderProviderContext(modelType);
|
||||||
|
|
@ -281,10 +168,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||||
{ modelName, valueProviderValue }
|
{ modelName, valueProviderValue }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions
|
|
||||||
{
|
var binderProvider = new EnumTypeModelBinderProvider(new MvcOptions());
|
||||||
SuppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType
|
|
||||||
});
|
|
||||||
var binder = binderProvider.GetBinder(binderProviderContext);
|
var binder = binderProvider.GetBinder(binderProviderContext);
|
||||||
return (bindingContext, binder);
|
return (bindingContext, binder);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
|
||||||
{
|
{
|
||||||
public class DefaultObjectValidatorTests
|
public class DefaultObjectValidatorTests
|
||||||
{
|
{
|
||||||
private readonly MvcOptions _options = new MvcOptions { AllowShortCircuitingValidationWhenNoValidatorsArePresent = true };
|
private readonly MvcOptions _options = new MvcOptions();
|
||||||
|
|
||||||
private ModelMetadataProvider MetadataProvider { get; } = TestModelMetadataProvider.CreateDefaultProvider();
|
private ModelMetadataProvider MetadataProvider { get; } = TestModelMetadataProvider.CreateDefaultProvider();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -275,53 +275,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
Assert.Equal("DisplayNameAttributeValue", context.DisplayMetadata.DisplayName());
|
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]
|
[Fact]
|
||||||
public void CreateDisplayMetadata_DisplayNameAttribute_OnEnum_CompatShimOn()
|
public void CreateDisplayMetadata_DisplayNameAttribute_OnEnum_CompatShimOn()
|
||||||
{
|
{
|
||||||
|
|
@ -337,7 +290,6 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
.Returns(() => sharedLocalizer.Object);
|
.Returns(() => sharedLocalizer.Object);
|
||||||
|
|
||||||
var localizationOptions = Options.Create(new MvcDataAnnotationsLocalizationOptions());
|
var localizationOptions = Options.Create(new MvcDataAnnotationsLocalizationOptions());
|
||||||
localizationOptions.Value.AllowDataAnnotationsLocalizationForEnumDisplayAttributes = true;
|
|
||||||
localizationOptions.Value.DataAnnotationLocalizerProvider = (type, stringLocalizerFactory) =>
|
localizationOptions.Value.DataAnnotationLocalizerProvider = (type, stringLocalizerFactory) =>
|
||||||
{
|
{
|
||||||
return stringLocalizerFactory.Create(typeof(EmptyClass));
|
return stringLocalizerFactory.Create(typeof(EmptyClass));
|
||||||
|
|
@ -1269,7 +1221,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
new RequiredAttribute(),
|
new RequiredAttribute(),
|
||||||
new StringLengthAttribute(5)
|
new StringLengthAttribute(5)
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.Equal(expected, actual: context.ValidationMetadata.ValidatorMetadata);
|
Assert.Equal(expected, actual: context.ValidationMetadata.ValidatorMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1580,7 +1532,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations
|
||||||
|
|
||||||
private class FooCompositeValidationAttribute : ValidationProviderAttribute
|
private class FooCompositeValidationAttribute : ValidationProviderAttribute
|
||||||
{
|
{
|
||||||
private IEnumerable<ValidationAttribute> _attributes;
|
private readonly IEnumerable<ValidationAttribute> _attributes;
|
||||||
|
|
||||||
public FooCompositeValidationAttribute(IEnumerable<ValidationAttribute> attributes)
|
public FooCompositeValidationAttribute(IEnumerable<ValidationAttribute> attributes)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -725,35 +725,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
treatEmptyInputAsDefaultValue: treatEmptyInputAsDefaultValue);
|
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
|
private sealed class User
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -15,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsFormatterMapping()
|
public void AddsFormatterMapping()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -30,7 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void DoesNotOverrideExistingMapping()
|
public void DoesNotOverrideExistingMapping()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||||
|
|
||||||
|
|
@ -46,7 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsInputFormatter()
|
public void AddsInputFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -60,7 +59,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsOutputFormatter()
|
public void AddsOutputFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -16,7 +14,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsFormatterMapping()
|
public void AddsFormatterMapping()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -31,7 +29,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void DoesNotOverrideExistingMapping()
|
public void DoesNotOverrideExistingMapping()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||||
|
|
||||||
|
|
@ -47,7 +45,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsInputFormatter()
|
public void AddsInputFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -61,7 +59,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
public void AddsOutputFormatter()
|
public void AddsOutputFormatter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
var optionsSetup = new XmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||||
var options = new MvcOptions();
|
var options = new MvcOptions();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
public void GetProvider_ReturnsNull_IfTypeDoesNotMatch()
|
public void GetProvider_ReturnsNull_IfTypeDoesNotMatch()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var xmlOptions = new MvcXmlOptions();
|
var providerFactory = new ProblemDetailsWrapperProviderFactory();
|
||||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
|
||||||
var context = new WrapperProviderContext(typeof(SerializableError), isSerialization: true);
|
var context = new WrapperProviderContext(typeof(SerializableError), isSerialization: true);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -26,8 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
public void GetProvider_ReturnsWrapper_ForProblemDetails()
|
public void GetProvider_ReturnsWrapper_ForProblemDetails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
|
var providerFactory = new ProblemDetailsWrapperProviderFactory();
|
||||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
|
||||||
var instance = new ProblemDetails();
|
var instance = new ProblemDetails();
|
||||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||||
|
|
||||||
|
|
@ -40,32 +38,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
Assert.Same(instance, wrapper.ProblemDetails);
|
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]
|
[Fact]
|
||||||
public void GetProvider_ReturnsWrapper_ForValidationProblemDetails()
|
public void GetProvider_ReturnsWrapper_ForValidationProblemDetails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
|
var providerFactory = new ProblemDetailsWrapperProviderFactory();
|
||||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
|
||||||
var instance = new ValidationProblemDetails();
|
var instance = new ValidationProblemDetails();
|
||||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||||
|
|
||||||
|
|
@ -78,32 +55,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||||
Assert.Same(instance, wrapper.ProblemDetails);
|
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]
|
[Fact]
|
||||||
public void GetProvider_ReturnsNull_ForCustomProblemDetails()
|
public void GetProvider_ReturnsNull_ForCustomProblemDetails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var xmlOptions = new MvcXmlOptions();
|
var providerFactory = new ProblemDetailsWrapperProviderFactory();
|
||||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
|
||||||
var instance = new CustomProblemDetails();
|
var instance = new CustomProblemDetails();
|
||||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
return new DefaultObjectValidator(
|
return new DefaultObjectValidator(
|
||||||
metadataProvider,
|
metadataProvider,
|
||||||
GetModelValidatorProviders(options),
|
GetModelValidatorProviders(options),
|
||||||
options?.Value ?? new MvcOptions { AllowShortCircuitingValidationWhenNoValidatorsArePresent = true });
|
options?.Value ?? new MvcOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IList<IModelValidatorProvider> GetModelValidatorProviders(IOptions<MvcOptions> options)
|
private static IList<IModelValidatorProvider> GetModelValidatorProviders(IOptions<MvcOptions> options)
|
||||||
|
|
@ -195,8 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
|
||||||
serviceCollection
|
serviceCollection
|
||||||
.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>()
|
.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>()
|
||||||
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
|
.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
|
||||||
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>()
|
.AddTransient<ILogger<DefaultAuthorizationService>, Logger<DefaultAuthorizationService>>();
|
||||||
.Configure<MvcOptions>(options => options.AllowShortCircuitingValidationWhenNoValidatorsArePresent = true);
|
|
||||||
|
|
||||||
if (updateOptions != null)
|
if (updateOptions != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions()));
|
||||||
|
|
||||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||||
defaultProvider.OnProvidersExecuting(context);
|
defaultProvider.OnProvidersExecuting(context);
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
|
||||||
var options = new RazorPagesOptions
|
var options = new RazorPagesOptions
|
||||||
{
|
{
|
||||||
AllowAreas = true,
|
|
||||||
// Setting this value should not affect area page lookup.
|
// Setting this value should not affect area page lookup.
|
||||||
RootDirectory = "/Files",
|
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]
|
[Fact]
|
||||||
public void OnProvidersExecuting_DoesNotAddAreaAndNonAreaRoutesForAPage()
|
public void OnProvidersExecuting_DoesNotAddAreaAndNonAreaRoutesForAPage()
|
||||||
{
|
{
|
||||||
|
|
@ -265,7 +226,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
|
|
||||||
var options = new RazorPagesOptions
|
var options = new RazorPagesOptions
|
||||||
{
|
{
|
||||||
AllowAreas = true,
|
|
||||||
RootDirectory = "/",
|
RootDirectory = "/",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -637,4 +597,4 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1036,24 +1036,6 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
public void OnGetUser() { }
|
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]
|
[Fact]
|
||||||
public void PopulateFilters_AddsDisallowOptionsRequestsPageFilter()
|
public void PopulateFilters_AddsDisallowOptionsRequestsPageFilter()
|
||||||
{
|
{
|
||||||
|
|
@ -1189,7 +1171,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
{
|
{
|
||||||
return new DefaultPageApplicationModelProvider(
|
return new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
{
|
{
|
||||||
var defaultProvider = new DefaultPageApplicationModelProvider(
|
var defaultProvider = new DefaultPageApplicationModelProvider(
|
||||||
TestModelMetadataProvider.CreateDefaultProvider(),
|
TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
Options.Create(new RazorPagesOptions { AllowDefaultHandlingForOptionsRequests = true }));
|
Options.Create(new RazorPagesOptions()));
|
||||||
|
|
||||||
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
var context = new PageApplicationModelProviderContext(new PageActionDescriptor(), typeInfo);
|
||||||
defaultProvider.OnProvidersExecuting(context);
|
defaultProvider.OnProvidersExecuting(context);
|
||||||
|
|
|
||||||
|
|
@ -80,17 +80,17 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||||
filter.Properties,
|
filter.Properties,
|
||||||
property =>
|
property =>
|
||||||
{
|
{
|
||||||
Assert.Equal("TempDataProperty-Test2", property.Key);
|
Assert.Equal("Test2", property.Key);
|
||||||
Assert.Equal(type.GetProperty(nameof(TestPageModel_OneTempDataProperty.Test2)), property.PropertyInfo);
|
Assert.Equal(type.GetProperty(nameof(TestPageModel_OneTempDataProperty.Test2)), property.PropertyInfo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString_IfCompatSwitchIsSet()
|
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var type = typeof(TestPageModel_OneTempDataProperty);
|
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 provider = new TempDataFilterPageApplicationModelProvider(options);
|
||||||
var context = CreateProviderContext(type);
|
var context = CreateProviderContext(type);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,55 +6,12 @@ using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
{
|
{
|
||||||
public class DefaultPageHandlerMethodSelectorTest
|
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]
|
[Fact]
|
||||||
public void NewBehavior_Select_ReturnsFuzzyMatchForHead_WhenNoHeadHandlerDefined()
|
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()
|
return new DefaultPageHandlerMethodSelector();
|
||||||
{
|
|
||||||
AllowMappingHeadRequestsToGetHandler = !legacyBehavior
|
|
||||||
});
|
|
||||||
return new DefaultPageHandlerMethodSelector(options);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,7 +20,6 @@ using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor;
|
using Microsoft.AspNetCore.Mvc.Razor;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
using Microsoft.AspNetCore.Mvc.TagHelpers;
|
||||||
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
using Microsoft.AspNetCore.Mvc.ViewComponents;
|
||||||
|
|
@ -382,13 +381,6 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
typeof(MvcCoreMvcOptionsSetup),
|
typeof(MvcCoreMvcOptionsSetup),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
typeof(IPostConfigureOptions<RazorPagesOptions>),
|
|
||||||
new[]
|
|
||||||
{
|
|
||||||
typeof(RazorPagesOptionsConfigureCompatibilityOptions),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
typeof(IActionConstraintProvider),
|
typeof(IActionConstraintProvider),
|
||||||
new Type[]
|
new Type[]
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
|
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]
|
[Theory]
|
||||||
|
|
@ -236,7 +236,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
|
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]
|
[Theory]
|
||||||
|
|
@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
|
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]
|
[Fact]
|
||||||
|
|
@ -282,7 +282,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
|
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]
|
[Fact]
|
||||||
|
|
@ -328,7 +328,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var attribute = Assert.Single(tagBuilder.Attributes, a => a.Key == "maxlength");
|
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]
|
[Theory]
|
||||||
|
|
@ -923,7 +923,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||||
private static IHtmlGenerator GetGenerator(IModelMetadataProvider metadataProvider)
|
private static IHtmlGenerator GetGenerator(IModelMetadataProvider metadataProvider)
|
||||||
{
|
{
|
||||||
var mvcViewOptionsAccessor = new Mock<IOptions<MvcViewOptions>>();
|
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 htmlEncoder = Mock.Of<HtmlEncoder>();
|
||||||
var antiforgery = new Mock<IAntiforgery>();
|
var antiforgery = new Mock<IAntiforgery>();
|
||||||
|
|
|
||||||
|
|
@ -85,15 +85,15 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Filters
|
||||||
Assert.NotNull(filter);
|
Assert.NotNull(filter);
|
||||||
var property = Assert.Single(filter.TempDataProperties);
|
var property = Assert.Single(filter.TempDataProperties);
|
||||||
Assert.Same(expected, property.PropertyInfo);
|
Assert.Same(expected, property.PropertyInfo);
|
||||||
Assert.Equal("TempDataProperty-Test2", property.Key);
|
Assert.Equal("Test2", property.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString_IfCompatSwitchIsSet()
|
public void OnProvidersExecuting_SetsKeyPrefixToEmptyString()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2));
|
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 type = typeof(TestController_OneTempDataProperty);
|
||||||
var provider = new TempDataApplicationModelProvider(options);
|
var provider = new TempDataApplicationModelProvider(options);
|
||||||
var context = GetContext(type);
|
var context = GetContext(type);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ namespace RazorPagesWebSite
|
||||||
.AddCookieTempDataProvider()
|
.AddCookieTempDataProvider()
|
||||||
.AddRazorPagesOptions(options =>
|
.AddRazorPagesOptions(options =>
|
||||||
{
|
{
|
||||||
options.AllowAreas = true;
|
|
||||||
options.Conventions.AuthorizePage("/Conventions/Auth");
|
options.Conventions.AuthorizePage("/Conventions/Auth");
|
||||||
options.Conventions.AuthorizeFolder("/Conventions/AuthFolder");
|
options.Conventions.AuthorizeFolder("/Conventions/AuthFolder");
|
||||||
options.Conventions.AuthorizeAreaFolder("Accounts", "/RequiresAuth");
|
options.Conventions.AuthorizeAreaFolder("Accounts", "/RequiresAuth");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue