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()); + context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory))) + .Returns(new NullLoggerFactory()); + + var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor); + + var controllerFactory = new Mock(); + controllerFactory.Setup(c => c.CreateController(It.IsAny())) + .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(), + new DiagnosticListener("Microsoft.AspNetCore"), + actionContext, + new IValueProviderFactory[0], + 200); + + // Act + await invoker.InvokeAsync(); + + // Assert + Assert.Equal(5, context.Object.Items["Result"]); + } + private TestControllerActionInvoker CreateInvoker( IFilterMetadata filter, bool actionThrows = false, - int maxAllowedErrorsInModelState = 200) + int maxAllowedErrorsInModelState = 200, + List valueProviderFactories = null) { - return CreateInvoker(new[] { filter }, actionThrows, maxAllowedErrorsInModelState); + return CreateInvoker(new[] { filter }, actionThrows, maxAllowedErrorsInModelState, valueProviderFactories); } private TestControllerActionInvoker CreateInvoker( IFilterMetadata[] filters, bool actionThrows = false, - int maxAllowedErrorsInModelState = 200) + int maxAllowedErrorsInModelState = 200, + List valueProviderFactories = null) { var actionDescriptor = new ControllerActionDescriptor() { @@ -2381,15 +2503,18 @@ namespace Microsoft.AspNetCore.Mvc.Internal if (actionThrows) { - actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(nameof(ControllerActionInvokerTest.ThrowingActionMethod)); + actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod( + nameof(ControllerActionInvokerTest.ThrowingActionMethod)); } else { - actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod(nameof(ControllerActionInvokerTest.ActionMethod)); + actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod( + nameof(ControllerActionInvokerTest.ActionMethod)); } actionDescriptor.ControllerTypeInfo = typeof(ControllerActionInvokerTest).GetTypeInfo(); - return CreateInvoker(filters, actionDescriptor, null, null, maxAllowedErrorsInModelState); + return CreateInvoker( + filters, actionDescriptor, null, null, maxAllowedErrorsInModelState, valueProviderFactories); } private TestControllerActionInvoker CreateInvoker( @@ -2417,7 +2542,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal ControllerActionDescriptor actionDescriptor, IControllerArgumentBinder controllerArgumentBinder, object controller, - int maxAllowedErrorsInModelState = 200) + int maxAllowedErrorsInModelState = 200, + List valueProviderFactories = null) { var httpContext = new Mock(MockBehavior.Loose); @@ -2512,6 +2638,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal .SetupGet(fp => fp.Order) .Returns(-1000); + if (valueProviderFactories == null) + { + valueProviderFactories = new List(); + } + var invoker = new TestControllerActionInvoker( new[] { filterProvider.Object }, new MockControllerFactory(controller ?? this), @@ -2519,72 +2650,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal new NullLoggerFactory().CreateLogger(), new DiagnosticListener("Microsoft.AspNetCore"), actionContext, - new IValueProviderFactory[0], + valueProviderFactories.AsReadOnly(), maxAllowedErrorsInModelState); return invoker; } - - [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()); - context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory))) - .Returns(new NullLoggerFactory()); - - var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor); - - var controllerFactory = new Mock(); - controllerFactory.Setup(c => c.CreateController(It.IsAny())) - .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(), - new DiagnosticListener("Microsoft.AspNetCore"), - actionContext, - new IValueProviderFactory[0], - 200); - - // Act - await invoker.InvokeAsync(); - - // Assert - Assert.Equal(5, context.Object.Items["Result"]); - } - public IActionResult ActionMethod() { return _result; @@ -2785,8 +2855,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal public bool ReleaseCalled { get; private set; } + public ControllerContext ControllerContext { get; private set; } + public object CreateController(ControllerContext context) { + ControllerContext = context; CreateCalled = true; return _controller; } @@ -2886,6 +2959,5 @@ namespace Microsoft.AspNetCore.Mvc.Internal return TaskCache.CompletedTask; } } - } } diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs index 5d68855e51..ecb7c631fb 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs @@ -2,6 +2,7 @@ // 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.Linq; using System.Net; using System.Net.Http; @@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests public async Task CanAuthorize(string testAction) { // Arrange & Act - var response = await Client.GetAsync("http://localhost/AuthorizeUser/"+testAction); + var response = await Client.GetAsync("http://localhost/AuthorizeUser/" + testAction); // Assert 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("\"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("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("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()); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/SkipStatusCodePagesAttributeTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/SkipStatusCodePagesAttributeTest.cs index 35e81cb9ff..ea0cc4952e 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/SkipStatusCodePagesAttributeTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/SkipStatusCodePagesAttributeTest.cs @@ -1,10 +1,12 @@ // 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.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Routing; using Xunit; @@ -43,7 +45,8 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test { return new ResourceExecutingContext( CreateActionContext(), - filters); + filters, + new List()); } private static ActionContext CreateActionContext() diff --git a/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs b/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs index 1fd3f7456e..f11c73dd22 100644 --- a/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs +++ b/test/WebSites/FiltersWebSite/Controllers/ResourceFilterController.cs @@ -28,6 +28,29 @@ namespace FiltersWebSite.Controllers 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 { public void OnResourceExecuted(ResourceExecutedContext context) diff --git a/test/WebSites/FiltersWebSite/Filters/DisableFormValueModelBindingAttribute.cs b/test/WebSites/FiltersWebSite/Filters/DisableFormValueModelBindingAttribute.cs new file mode 100644 index 0000000000..9536d7a565 --- /dev/null +++ b/test/WebSites/FiltersWebSite/Filters/DisableFormValueModelBindingAttribute.cs @@ -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() + .FirstOrDefault(); + if (formValueProviderFactory != null) + { + context.ValueProviderFactories.Remove(formValueProviderFactory); + } + + var jqueryFormValueProviderFactory = context.ValueProviderFactories + .OfType() + .FirstOrDefault(); + if (jqueryFormValueProviderFactory != null) + { + context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory); + } + } + + public void OnResourceExecuted(ResourceExecutedContext context) + { + } + } +}