Added ValueProviderFactories to ResourceFilterExecutingContext
This enables removing value provider factories from model binding(which is needed in some scenarios like large file uploads)
This commit is contained in:
parent
df4eb283b2
commit
20a2e748ec
|
|
@ -31,6 +31,10 @@
|
||||||
"imports": [
|
"imports": [
|
||||||
"portable-net45+wp80+win8+wpa81+dnxcore50"
|
"portable-net45+wp80+win8+wpa81+dnxcore50"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"Microsoft.DotNet.Watcher.Tools": {
|
||||||
|
"version": "1.0.0-*",
|
||||||
|
"imports": "portable-net451+win8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// 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.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Filters
|
namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
{
|
{
|
||||||
|
|
@ -16,9 +18,19 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actionContext">The <see cref="ActionContext"/>.</param>
|
/// <param name="actionContext">The <see cref="ActionContext"/>.</param>
|
||||||
/// <param name="filters">The list of <see cref="IFilterMetadata"/> instances.</param>
|
/// <param name="filters">The list of <see cref="IFilterMetadata"/> instances.</param>
|
||||||
public ResourceExecutingContext(ActionContext actionContext, IList<IFilterMetadata> filters)
|
/// <param name="valueProviderFactories">The list of <see cref="IValueProviderFactory"/> instances.</param>
|
||||||
|
public ResourceExecutingContext(
|
||||||
|
ActionContext actionContext,
|
||||||
|
IList<IFilterMetadata> filters,
|
||||||
|
IList<IValueProviderFactory> valueProviderFactories)
|
||||||
: base(actionContext, filters)
|
: base(actionContext, filters)
|
||||||
{
|
{
|
||||||
|
if (valueProviderFactories == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(valueProviderFactories));
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueProviderFactories = valueProviderFactories;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -29,5 +41,10 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
/// short-circuit execution of additional resource filters and the action itself.
|
/// short-circuit execution of additional resource filters and the action itself.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual IActionResult Result { get; set; }
|
public virtual IActionResult Result { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of <see cref="IValueProviderFactory"/> instances used by model binding.
|
||||||
|
/// </summary>
|
||||||
|
public IList<IValueProviderFactory> ValueProviderFactories { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(valueProviderFactories));
|
throw new ArgumentNullException(nameof(valueProviderFactories));
|
||||||
}
|
}
|
||||||
|
|
||||||
_controllerFactory = controllerFactory;
|
_controllerFactory = controllerFactory;
|
||||||
_controllerArgumentBinder = controllerArgumentBinder;
|
_controllerArgumentBinder = controllerArgumentBinder;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
@ -216,7 +216,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
{
|
{
|
||||||
_cursor.Reset();
|
_cursor.Reset();
|
||||||
|
|
||||||
_resourceExecutingContext = new ResourceExecutingContext(_controllerContext, _filters);
|
_resourceExecutingContext = new ResourceExecutingContext(
|
||||||
|
_controllerContext,
|
||||||
|
_filters,
|
||||||
|
_controllerContext.ValueProviderFactories);
|
||||||
|
|
||||||
return InvokeResourceFilterAsync();
|
return InvokeResourceFilterAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -266,7 +270,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
_diagnosticSource.AfterOnResourceExecution(_resourceExecutedContext, item.FilterAsync);
|
_diagnosticSource.AfterOnResourceExecution(_resourceExecutedContext, item.FilterAsync);
|
||||||
|
|
||||||
if (_resourceExecutingContext.Result != null)
|
if (_resourceExecutingContext.Result != null)
|
||||||
{
|
{
|
||||||
_logger.ResourceFilterShortCircuited(item.FilterAsync);
|
_logger.ResourceFilterShortCircuited(item.FilterAsync);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||||
using Microsoft.AspNetCore.Mvc.Internal;
|
using Microsoft.AspNetCore.Mvc.Internal;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -309,7 +310,10 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
};
|
};
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
||||||
|
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
|
actionContext,
|
||||||
|
new[] { consumesFilter },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
@ -336,7 +340,10 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
};
|
};
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
||||||
|
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
|
actionContext,
|
||||||
|
new[] { consumesFilter },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
@ -361,7 +368,10 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
new List<FilterDescriptor>() { new FilterDescriptor(consumesFilter, FilterScope.Action) }
|
new List<FilterDescriptor>() { new FilterDescriptor(consumesFilter, FilterScope.Action) }
|
||||||
};
|
};
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
|
actionContext,
|
||||||
|
new[] { consumesFilter },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
consumesFilter.OnResourceExecuting(resourceExecutingContext);
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
// 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.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Mvc.TestCommon;
|
using Microsoft.AspNetCore.Mvc.TestCommon;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -87,7 +89,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
ac,
|
ac,
|
||||||
new IFilterMetadata[] { });
|
new IFilterMetadata[] { },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
var filter = new FormatFilter(mockObjects.OptionsManager);
|
var filter = new FormatFilter(mockObjects.OptionsManager);
|
||||||
|
|
||||||
|
|
@ -322,7 +325,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
actionContext,
|
actionContext,
|
||||||
new IFilterMetadata[] { });
|
new IFilterMetadata[] { },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
var filter = new FormatFilter(mockObjects.OptionsManager);
|
var filter = new FormatFilter(mockObjects.OptionsManager);
|
||||||
|
|
||||||
|
|
@ -356,7 +360,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
|
|
||||||
var resourceExecutingContext = new ResourceExecutingContext(
|
var resourceExecutingContext = new ResourceExecutingContext(
|
||||||
actionContext,
|
actionContext,
|
||||||
new IFilterMetadata[] { });
|
new IFilterMetadata[] { },
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
|
|
||||||
var filter = new FormatFilter(mockObjects.OptionsManager);
|
var filter = new FormatFilter(mockObjects.OptionsManager);
|
||||||
|
|
||||||
|
|
@ -392,7 +397,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
var context = new ResourceExecutingContext(
|
var context = new ResourceExecutingContext(
|
||||||
MockActionContext,
|
MockActionContext,
|
||||||
filters);
|
filters,
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1862,6 +1862,66 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
Assert.False(invoker.ControllerFactory.CreateCalled);
|
Assert.False(invoker.ControllerFactory.CreateCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddingValueProviderFactory_AtResourceFilter_IsAvailableInControllerContext()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var valueProviderFactory2 = Mock.Of<IValueProviderFactory>();
|
||||||
|
var resourceFilter = new Mock<IResourceFilter>();
|
||||||
|
resourceFilter
|
||||||
|
.Setup(f => f.OnResourceExecuting(It.IsAny<ResourceExecutingContext>()))
|
||||||
|
.Callback<ResourceExecutingContext>((resourceExecutingContext) =>
|
||||||
|
{
|
||||||
|
resourceExecutingContext.ValueProviderFactories.Add(valueProviderFactory2);
|
||||||
|
});
|
||||||
|
var valueProviderFactory1 = Mock.Of<IValueProviderFactory>();
|
||||||
|
var valueProviderFactories = new List<IValueProviderFactory>();
|
||||||
|
valueProviderFactories.Add(valueProviderFactory1);
|
||||||
|
|
||||||
|
var invoker = CreateInvoker(
|
||||||
|
new IFilterMetadata[] { resourceFilter.Object }, valueProviderFactories: valueProviderFactories);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var controllerContext = invoker.ControllerFactory.ControllerContext;
|
||||||
|
Assert.NotNull(controllerContext);
|
||||||
|
Assert.Equal(2, controllerContext.ValueProviderFactories.Count);
|
||||||
|
Assert.Same(valueProviderFactory1, controllerContext.ValueProviderFactories[0]);
|
||||||
|
Assert.Same(valueProviderFactory2, controllerContext.ValueProviderFactories[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeletingValueProviderFactory_AtResourceFilter_IsNotAvailableInControllerContext()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var resourceFilter = new Mock<IResourceFilter>();
|
||||||
|
resourceFilter
|
||||||
|
.Setup(f => f.OnResourceExecuting(It.IsAny<ResourceExecutingContext>()))
|
||||||
|
.Callback<ResourceExecutingContext>((resourceExecutingContext) =>
|
||||||
|
{
|
||||||
|
resourceExecutingContext.ValueProviderFactories.RemoveAt(0);
|
||||||
|
});
|
||||||
|
var valueProviderFactory1 = Mock.Of<IValueProviderFactory>();
|
||||||
|
var valueProviderFactory2 = Mock.Of<IValueProviderFactory>();
|
||||||
|
var valueProviderFactories = new List<IValueProviderFactory>();
|
||||||
|
valueProviderFactories.Add(valueProviderFactory1);
|
||||||
|
valueProviderFactories.Add(valueProviderFactory2);
|
||||||
|
|
||||||
|
var invoker = CreateInvoker(
|
||||||
|
new IFilterMetadata[] { resourceFilter.Object }, valueProviderFactories: valueProviderFactories);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var controllerContext = invoker.ControllerFactory.ControllerContext;
|
||||||
|
Assert.NotNull(controllerContext);
|
||||||
|
Assert.Equal(1, controllerContext.ValueProviderFactories.Count);
|
||||||
|
Assert.Same(valueProviderFactory2, controllerContext.ValueProviderFactories[0]);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task MaxAllowedErrorsIsSet_BeforeCallingAuthorizationFilter()
|
public async Task MaxAllowedErrorsIsSet_BeforeCallingAuthorizationFilter()
|
||||||
{
|
{
|
||||||
|
|
@ -2038,8 +2098,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var invoker = CreateInvoker(
|
var invoker = CreateInvoker(
|
||||||
new[] { filter.Object },
|
new[] { filter.Object },
|
||||||
nameof(TestController.EchoWithException),
|
nameof(TestController.EchoWithException),
|
||||||
new Dictionary<string, object>() { { "input", inputString } });
|
new Dictionary<string, object>() { { "input", inputString } });
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
|
|
@ -2061,8 +2121,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var invoker = CreateInvoker(
|
var invoker = CreateInvoker(
|
||||||
new[] { filter.Object },
|
new[] { filter.Object },
|
||||||
nameof(TestController.EchoWithDefaultValue),
|
nameof(TestController.EchoWithDefaultValue),
|
||||||
new Dictionary<string, object>());
|
new Dictionary<string, object>());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -2088,7 +2148,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
||||||
var invoker = CreateInvoker(
|
var invoker = CreateInvoker(
|
||||||
new[] { filter.Object },
|
new[] { filter.Object },
|
||||||
nameof(TestController.EchoWithDefaultValue),
|
nameof(TestController.EchoWithDefaultValue),
|
||||||
new Dictionary<string, object>() { { "input", inputString } });
|
new Dictionary<string, object>() { { "input", inputString } });
|
||||||
|
|
||||||
|
|
@ -2360,18 +2420,80 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
+ "'.");
|
+ "'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Invoke_UsesDefaultValuesIfNotBound()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var actionDescriptor = new ControllerActionDescriptor
|
||||||
|
{
|
||||||
|
ControllerTypeInfo = typeof(TestController).GetTypeInfo(),
|
||||||
|
BoundProperties = new List<ParameterDescriptor>(),
|
||||||
|
MethodInfo = typeof(TestController).GetTypeInfo()
|
||||||
|
.DeclaredMethods
|
||||||
|
.First(m => m.Name.Equals("ActionMethodWithDefaultValues", StringComparison.Ordinal)),
|
||||||
|
|
||||||
|
Parameters = new List<ParameterDescriptor>
|
||||||
|
{
|
||||||
|
new ParameterDescriptor
|
||||||
|
{
|
||||||
|
Name = "value",
|
||||||
|
ParameterType = typeof(int),
|
||||||
|
BindingInfo = new BindingInfo(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FilterDescriptors = new List<FilterDescriptor>()
|
||||||
|
};
|
||||||
|
|
||||||
|
var context = new Mock<HttpContext>();
|
||||||
|
context.SetupGet(c => c.Items)
|
||||||
|
.Returns(new Dictionary<object, object>());
|
||||||
|
context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory)))
|
||||||
|
.Returns(new NullLoggerFactory());
|
||||||
|
|
||||||
|
var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);
|
||||||
|
|
||||||
|
var controllerFactory = new Mock<IControllerFactory>();
|
||||||
|
controllerFactory.Setup(c => c.CreateController(It.IsAny<ControllerContext>()))
|
||||||
|
.Returns(new TestController());
|
||||||
|
|
||||||
|
var metadataProvider = new EmptyModelMetadataProvider();
|
||||||
|
|
||||||
|
var argumentBinder = new ControllerArgumentBinder(
|
||||||
|
metadataProvider,
|
||||||
|
TestModelBinderFactory.CreateDefault(metadataProvider),
|
||||||
|
new DefaultObjectValidator(metadataProvider, new IModelValidatorProvider[0]));
|
||||||
|
|
||||||
|
var invoker = new ControllerActionInvoker(
|
||||||
|
CreateFilterCache(),
|
||||||
|
controllerFactory.Object,
|
||||||
|
argumentBinder,
|
||||||
|
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
|
||||||
|
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||||
|
actionContext,
|
||||||
|
new IValueProviderFactory[0],
|
||||||
|
200);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(5, context.Object.Items["Result"]);
|
||||||
|
}
|
||||||
|
|
||||||
private TestControllerActionInvoker CreateInvoker(
|
private TestControllerActionInvoker CreateInvoker(
|
||||||
IFilterMetadata filter,
|
IFilterMetadata filter,
|
||||||
bool actionThrows = false,
|
bool actionThrows = false,
|
||||||
int maxAllowedErrorsInModelState = 200)
|
int maxAllowedErrorsInModelState = 200,
|
||||||
|
List<IValueProviderFactory> valueProviderFactories = null)
|
||||||
{
|
{
|
||||||
return CreateInvoker(new[] { filter }, actionThrows, maxAllowedErrorsInModelState);
|
return CreateInvoker(new[] { filter }, actionThrows, maxAllowedErrorsInModelState, valueProviderFactories);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestControllerActionInvoker CreateInvoker(
|
private TestControllerActionInvoker CreateInvoker(
|
||||||
IFilterMetadata[] filters,
|
IFilterMetadata[] filters,
|
||||||
bool actionThrows = false,
|
bool actionThrows = false,
|
||||||
int maxAllowedErrorsInModelState = 200)
|
int maxAllowedErrorsInModelState = 200,
|
||||||
|
List<IValueProviderFactory> valueProviderFactories = null)
|
||||||
{
|
{
|
||||||
var actionDescriptor = new ControllerActionDescriptor()
|
var actionDescriptor = new ControllerActionDescriptor()
|
||||||
{
|
{
|
||||||
|
|
@ -2381,15 +2503,18 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
if (actionThrows)
|
if (actionThrows)
|
||||||
{
|
{
|
||||||
actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(nameof(ControllerActionInvokerTest.ThrowingActionMethod));
|
actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(
|
||||||
|
nameof(ControllerActionInvokerTest.ThrowingActionMethod));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(nameof(ControllerActionInvokerTest.ActionMethod));
|
actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(
|
||||||
|
nameof(ControllerActionInvokerTest.ActionMethod));
|
||||||
}
|
}
|
||||||
actionDescriptor.ControllerTypeInfo = typeof(ControllerActionInvokerTest).GetTypeInfo();
|
actionDescriptor.ControllerTypeInfo = typeof(ControllerActionInvokerTest).GetTypeInfo();
|
||||||
|
|
||||||
return CreateInvoker(filters, actionDescriptor, null, null, maxAllowedErrorsInModelState);
|
return CreateInvoker(
|
||||||
|
filters, actionDescriptor, null, null, maxAllowedErrorsInModelState, valueProviderFactories);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestControllerActionInvoker CreateInvoker(
|
private TestControllerActionInvoker CreateInvoker(
|
||||||
|
|
@ -2417,7 +2542,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
ControllerActionDescriptor actionDescriptor,
|
ControllerActionDescriptor actionDescriptor,
|
||||||
IControllerArgumentBinder controllerArgumentBinder,
|
IControllerArgumentBinder controllerArgumentBinder,
|
||||||
object controller,
|
object controller,
|
||||||
int maxAllowedErrorsInModelState = 200)
|
int maxAllowedErrorsInModelState = 200,
|
||||||
|
List<IValueProviderFactory> valueProviderFactories = null)
|
||||||
{
|
{
|
||||||
var httpContext = new Mock<HttpContext>(MockBehavior.Loose);
|
var httpContext = new Mock<HttpContext>(MockBehavior.Loose);
|
||||||
|
|
||||||
|
|
@ -2512,6 +2638,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
.SetupGet(fp => fp.Order)
|
.SetupGet(fp => fp.Order)
|
||||||
.Returns(-1000);
|
.Returns(-1000);
|
||||||
|
|
||||||
|
if (valueProviderFactories == null)
|
||||||
|
{
|
||||||
|
valueProviderFactories = new List<IValueProviderFactory>();
|
||||||
|
}
|
||||||
|
|
||||||
var invoker = new TestControllerActionInvoker(
|
var invoker = new TestControllerActionInvoker(
|
||||||
new[] { filterProvider.Object },
|
new[] { filterProvider.Object },
|
||||||
new MockControllerFactory(controller ?? this),
|
new MockControllerFactory(controller ?? this),
|
||||||
|
|
@ -2519,72 +2650,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
|
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
|
||||||
new DiagnosticListener("Microsoft.AspNetCore"),
|
new DiagnosticListener("Microsoft.AspNetCore"),
|
||||||
actionContext,
|
actionContext,
|
||||||
new IValueProviderFactory[0],
|
valueProviderFactories.AsReadOnly(),
|
||||||
maxAllowedErrorsInModelState);
|
maxAllowedErrorsInModelState);
|
||||||
return invoker;
|
return invoker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task Invoke_UsesDefaultValuesIfNotBound()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var actionDescriptor = new ControllerActionDescriptor
|
|
||||||
{
|
|
||||||
ControllerTypeInfo = typeof(TestController).GetTypeInfo(),
|
|
||||||
BoundProperties = new List<ParameterDescriptor>(),
|
|
||||||
MethodInfo = typeof(TestController).GetTypeInfo()
|
|
||||||
.DeclaredMethods
|
|
||||||
.First(m => m.Name.Equals("ActionMethodWithDefaultValues", StringComparison.Ordinal)),
|
|
||||||
|
|
||||||
Parameters = new List<ParameterDescriptor>
|
|
||||||
{
|
|
||||||
new ParameterDescriptor
|
|
||||||
{
|
|
||||||
Name = "value",
|
|
||||||
ParameterType = typeof(int),
|
|
||||||
BindingInfo = new BindingInfo(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
FilterDescriptors = new List<FilterDescriptor>()
|
|
||||||
};
|
|
||||||
|
|
||||||
var context = new Mock<HttpContext>();
|
|
||||||
context.SetupGet(c => c.Items)
|
|
||||||
.Returns(new Dictionary<object, object>());
|
|
||||||
context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory)))
|
|
||||||
.Returns(new NullLoggerFactory());
|
|
||||||
|
|
||||||
var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);
|
|
||||||
|
|
||||||
var controllerFactory = new Mock<IControllerFactory>();
|
|
||||||
controllerFactory.Setup(c => c.CreateController(It.IsAny<ControllerContext>()))
|
|
||||||
.Returns(new TestController());
|
|
||||||
|
|
||||||
var metadataProvider = new EmptyModelMetadataProvider();
|
|
||||||
|
|
||||||
var argumentBinder = new ControllerArgumentBinder(
|
|
||||||
metadataProvider,
|
|
||||||
TestModelBinderFactory.CreateDefault(metadataProvider),
|
|
||||||
new DefaultObjectValidator(metadataProvider, new IModelValidatorProvider[0]));
|
|
||||||
|
|
||||||
var invoker = new ControllerActionInvoker(
|
|
||||||
CreateFilterCache(),
|
|
||||||
controllerFactory.Object,
|
|
||||||
argumentBinder,
|
|
||||||
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
|
|
||||||
new DiagnosticListener("Microsoft.AspNetCore"),
|
|
||||||
actionContext,
|
|
||||||
new IValueProviderFactory[0],
|
|
||||||
200);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await invoker.InvokeAsync();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(5, context.Object.Items["Result"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IActionResult ActionMethod()
|
public IActionResult ActionMethod()
|
||||||
{
|
{
|
||||||
return _result;
|
return _result;
|
||||||
|
|
@ -2785,8 +2855,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
public bool ReleaseCalled { get; private set; }
|
public bool ReleaseCalled { get; private set; }
|
||||||
|
|
||||||
|
public ControllerContext ControllerContext { get; private set; }
|
||||||
|
|
||||||
public object CreateController(ControllerContext context)
|
public object CreateController(ControllerContext context)
|
||||||
{
|
{
|
||||||
|
ControllerContext = context;
|
||||||
CreateCalled = true;
|
CreateCalled = true;
|
||||||
return _controller;
|
return _controller;
|
||||||
}
|
}
|
||||||
|
|
@ -2886,6 +2959,5 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
return TaskCache.CompletedTask;
|
return TaskCache.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
public async Task CanAuthorize(string testAction)
|
public async Task CanAuthorize(string testAction)
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var response = await Client.GetAsync("http://localhost/AuthorizeUser/"+testAction);
|
var response = await Client.GetAsync("http://localhost/AuthorizeUser/" + testAction);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
@ -509,5 +510,31 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
|
Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
|
||||||
Assert.Equal("\"someValue\"", await response.Content.ReadAsStringAsync());
|
Assert.Equal("\"someValue\"", await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ResourceFilter_RemovingValueProviderFactoriesForAnAction_DoesNotAffectOtherActions()
|
||||||
|
{
|
||||||
|
// Request to an action which does NOT expect form value model binding
|
||||||
|
// Arrange & Act
|
||||||
|
var response = await Client.PostAsync(
|
||||||
|
"http://localhost/ResourceFilter/FormValueModelBinding_Disabled",
|
||||||
|
new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("SampleInt", "10") }));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("text/plain", response.Content.Headers.ContentType.MediaType);
|
||||||
|
Assert.Equal("Data:0", await response.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
|
// Request to an action which expects form value model binding
|
||||||
|
// Arrange & Act
|
||||||
|
response = await Client.PostAsync(
|
||||||
|
"http://localhost/ResourceFilter/FormValueModelBinding_Enabled",
|
||||||
|
new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("SampleInt", "10") }));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("text/plain", response.Content.Headers.ContentType.MediaType);
|
||||||
|
Assert.Equal("Data:10", await response.Content.ReadAsStringAsync());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
// 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.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -43,7 +45,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
|
||||||
{
|
{
|
||||||
return new ResourceExecutingContext(
|
return new ResourceExecutingContext(
|
||||||
CreateActionContext(),
|
CreateActionContext(),
|
||||||
filters);
|
filters,
|
||||||
|
new List<IValueProviderFactory>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,29 @@ namespace FiltersWebSite.Controllers
|
||||||
return "NeverGetsExecuted";
|
return "NeverGetsExecuted";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public IActionResult FormValueModelBinding_Enabled(DummyClass dc)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok("Data:" + dc?.SampleInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[DisableFormValueModelBinding]
|
||||||
|
public IActionResult FormValueModelBinding_Disabled(DummyClass dc)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok("Data:" + dc?.SampleInt);
|
||||||
|
}
|
||||||
|
|
||||||
private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter
|
private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter
|
||||||
{
|
{
|
||||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
|
||||||
|
namespace FiltersWebSite
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
|
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||||
|
{
|
||||||
|
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||||
|
{
|
||||||
|
var formValueProviderFactory = context.ValueProviderFactories
|
||||||
|
.OfType<FormValueProviderFactory>()
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (formValueProviderFactory != null)
|
||||||
|
{
|
||||||
|
context.ValueProviderFactories.Remove(formValueProviderFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
var jqueryFormValueProviderFactory = context.ValueProviderFactories
|
||||||
|
.OfType<JQueryFormValueProviderFactory>()
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (jqueryFormValueProviderFactory != null)
|
||||||
|
{
|
||||||
|
context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue