diff --git a/samples/MvcSandbox/project.json b/samples/MvcSandbox/project.json
index eaf65ebb94..9e510e769f 100644
--- a/samples/MvcSandbox/project.json
+++ b/samples/MvcSandbox/project.json
@@ -31,6 +31,10 @@
"imports": [
"portable-net45+wp80+win8+wpa81+dnxcore50"
]
+ },
+ "Microsoft.DotNet.Watcher.Tools": {
+ "version": "1.0.0-*",
+ "imports": "portable-net451+win8"
}
},
"frameworks": {
diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs
index e0007a4006..46378b3760 100644
--- a/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs
@@ -1,7 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace Microsoft.AspNetCore.Mvc.Filters
{
@@ -16,9 +18,19 @@ namespace Microsoft.AspNetCore.Mvc.Filters
///
/// The .
/// The list of instances.
- public ResourceExecutingContext(ActionContext actionContext, IList filters)
+ /// The list of instances.
+ public ResourceExecutingContext(
+ ActionContext actionContext,
+ IList filters,
+ IList valueProviderFactories)
: base(actionContext, filters)
{
+ if (valueProviderFactories == null)
+ {
+ throw new ArgumentNullException(nameof(valueProviderFactories));
+ }
+
+ ValueProviderFactories = valueProviderFactories;
}
///
@@ -29,5 +41,10 @@ namespace Microsoft.AspNetCore.Mvc.Filters
/// short-circuit execution of additional resource filters and the action itself.
///
public virtual IActionResult Result { get; set; }
+
+ ///
+ /// Gets the list of instances used by model binding.
+ ///
+ public IList ValueProviderFactories { get; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionInvoker.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionInvoker.cs
index 367b17a061..939f481539 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionInvoker.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/ControllerActionInvoker.cs
@@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
{
throw new ArgumentNullException(nameof(valueProviderFactories));
}
-
+
_controllerFactory = controllerFactory;
_controllerArgumentBinder = controllerArgumentBinder;
_logger = logger;
@@ -216,7 +216,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
{
_cursor.Reset();
- _resourceExecutingContext = new ResourceExecutingContext(_controllerContext, _filters);
+ _resourceExecutingContext = new ResourceExecutingContext(
+ _controllerContext,
+ _filters,
+ _controllerContext.ValueProviderFactories);
+
return InvokeResourceFilterAsync();
}
@@ -266,7 +270,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
}
_diagnosticSource.AfterOnResourceExecution(_resourceExecutedContext, item.FilterAsync);
-
+
if (_resourceExecutingContext.Result != null)
{
_logger.ResourceFilterShortCircuited(item.FilterAsync);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs
index e17e9418a2..a2738ed9a2 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ConsumesAttributeTests.cs
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing;
using Microsoft.Net.Http.Headers;
using Moq;
@@ -309,7 +310,10 @@ namespace Microsoft.AspNetCore.Mvc
};
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
- var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
+ var resourceExecutingContext = new ResourceExecutingContext(
+ actionContext,
+ new[] { consumesFilter },
+ new List());
// Act
consumesFilter.OnResourceExecuting(resourceExecutingContext);
@@ -336,7 +340,10 @@ namespace Microsoft.AspNetCore.Mvc
};
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
- var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
+ var resourceExecutingContext = new ResourceExecutingContext(
+ actionContext,
+ new[] { consumesFilter },
+ new List());
// Act
consumesFilter.OnResourceExecuting(resourceExecutingContext);
@@ -361,7 +368,10 @@ namespace Microsoft.AspNetCore.Mvc
new List() { new FilterDescriptor(consumesFilter, FilterScope.Action) }
};
var actionContext = new ActionContext(httpContext, new RouteData(), actionWithConstraint);
- var resourceExecutingContext = new ResourceExecutingContext(actionContext, new[] { consumesFilter });
+ var resourceExecutingContext = new ResourceExecutingContext(
+ actionContext,
+ new[] { consumesFilter },
+ new List());
// Act
consumesFilter.OnResourceExecuting(resourceExecutingContext);
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs
index 43073d3b48..ee1268d2fd 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatFilterTest.cs
@@ -2,9 +2,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Buffers;
+using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
@@ -87,7 +89,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
var resourceExecutingContext = new ResourceExecutingContext(
ac,
- new IFilterMetadata[] { });
+ new IFilterMetadata[] { },
+ new List());
var filter = new FormatFilter(mockObjects.OptionsManager);
@@ -322,7 +325,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
var resourceExecutingContext = new ResourceExecutingContext(
actionContext,
- new IFilterMetadata[] { });
+ new IFilterMetadata[] { },
+ new List());
var filter = new FormatFilter(mockObjects.OptionsManager);
@@ -356,7 +360,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
var resourceExecutingContext = new ResourceExecutingContext(
actionContext,
- new IFilterMetadata[] { });
+ new IFilterMetadata[] { },
+ new List());
var filter = new FormatFilter(mockObjects.OptionsManager);
@@ -392,7 +397,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{
var context = new ResourceExecutingContext(
MockActionContext,
- filters);
+ filters,
+ new List());
return context;
}
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs
index 9224dec9f7..bbd81d31ca 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Internal/ControllerActionInvokerTest.cs
@@ -1862,6 +1862,66 @@ namespace Microsoft.AspNetCore.Mvc.Internal
Assert.False(invoker.ControllerFactory.CreateCalled);
}
+ [Fact]
+ public async Task AddingValueProviderFactory_AtResourceFilter_IsAvailableInControllerContext()
+ {
+ // Arrange
+ var valueProviderFactory2 = Mock.Of();
+ var resourceFilter = new Mock();
+ resourceFilter
+ .Setup(f => f.OnResourceExecuting(It.IsAny()))
+ .Callback((resourceExecutingContext) =>
+ {
+ resourceExecutingContext.ValueProviderFactories.Add(valueProviderFactory2);
+ });
+ var valueProviderFactory1 = Mock.Of();
+ var valueProviderFactories = new List();
+ 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();
+ resourceFilter
+ .Setup(f => f.OnResourceExecuting(It.IsAny()))
+ .Callback((resourceExecutingContext) =>
+ {
+ resourceExecutingContext.ValueProviderFactories.RemoveAt(0);
+ });
+ var valueProviderFactory1 = Mock.Of();
+ var valueProviderFactory2 = Mock.Of();
+ var valueProviderFactories = new List();
+ 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]
public async Task MaxAllowedErrorsIsSet_BeforeCallingAuthorizationFilter()
{
@@ -2038,8 +2098,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
.Verifiable();
var invoker = CreateInvoker(
- new[] { filter.Object },
- nameof(TestController.EchoWithException),
+ new[] { filter.Object },
+ nameof(TestController.EchoWithException),
new Dictionary() { { "input", inputString } });
// Act & Assert
@@ -2061,8 +2121,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
.Verifiable();
var invoker = CreateInvoker(
- new[] { filter.Object },
- nameof(TestController.EchoWithDefaultValue),
+ new[] { filter.Object },
+ nameof(TestController.EchoWithDefaultValue),
new Dictionary());
// Act
@@ -2088,7 +2148,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
.Verifiable();
var invoker = CreateInvoker(
- new[] { filter.Object },
+ new[] { filter.Object },
nameof(TestController.EchoWithDefaultValue),
new Dictionary() { { "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(),
+ MethodInfo = typeof(TestController).GetTypeInfo()
+ .DeclaredMethods
+ .First(m => m.Name.Equals("ActionMethodWithDefaultValues", StringComparison.Ordinal)),
+
+ Parameters = new List
+ {
+ new ParameterDescriptor
+ {
+ Name = "value",
+ ParameterType = typeof(int),
+ BindingInfo = new BindingInfo(),
+ }
+ },
+ FilterDescriptors = new List()
+ };
+
+ var context = new Mock();
+ context.SetupGet(c => c.Items)
+ .Returns(new Dictionary