diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs index 34b96c96e3..770acb2bd2 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/Filters/ResourceExecutingContext.cs @@ -2,15 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; namespace Microsoft.AspNetCore.Mvc.Filters { /// - /// A context for resource filters. Allows modification of services and values used for - /// model binding. + /// A context for resource filters. /// public class ResourceExecutingContext : FilterContext { @@ -23,34 +19,14 @@ namespace Microsoft.AspNetCore.Mvc.Filters : base(actionContext, filters) { } - - /// - /// Gets or sets the list of instances used by model binding. - /// - public virtual FormatterCollection InputFormatters { get; set; } - - /// - /// Gets or sets the list of instances used by model binding. - /// - public virtual IList ModelBinders { get; set; } - + /// /// Gets or sets the result of the action to be executed. /// /// /// Setting to a non-null value inside a resource filter will - /// short-circuit execution of additional resource filtes and the action itself. + /// short-circuit execution of additional resource filters and the action itself. /// public virtual IActionResult Result { get; set; } - - /// - /// Gets or sets the list of instances used by model binding. - /// - public IList ValueProviderFactories { get; set; } - - /// - /// Gets or sets the list of instances used by model binding. - /// - public IList ValidatorProviders { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterActionInvoker.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterActionInvoker.cs index 3a9ab93d62..a81f0febce 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterActionInvoker.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/FilterActionInvoker.cs @@ -255,15 +255,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal { _cursor.Reset(); - var context = new ResourceExecutingContext(Context, _filters); - - context.InputFormatters = new FormatterCollection( - new CopyOnWriteList(_inputFormatters)); - context.ModelBinders = new CopyOnWriteList(_modelBinders); - context.ValidatorProviders = new CopyOnWriteList(_modelValidatorProviders); - context.ValueProviderFactories = new CopyOnWriteList(_valueProviderFactories); - - _resourceExecutingContext = context; + _resourceExecutingContext = new ResourceExecutingContext(Context, _filters); return InvokeResourceFilterAsync(); } @@ -362,16 +354,17 @@ namespace Microsoft.AspNetCore.Mvc.Internal { // We've reached the end of resource filters, so move to setting up state to invoke model // binding. - Context.InputFormatters = _resourceExecutingContext.InputFormatters; - Context.ModelBinders = _resourceExecutingContext.ModelBinders; - Context.ValidatorProviders = _resourceExecutingContext.ValidatorProviders; + Context.InputFormatters = new FormatterCollection( + new CopyOnWriteList(_inputFormatters)); + Context.ModelBinders = new CopyOnWriteList(_modelBinders); + Context.ValidatorProviders = new CopyOnWriteList(_modelValidatorProviders); var valueProviders = new List(); var factoryContext = new ValueProviderFactoryContext(Context); - for (var i = 0; i < _resourceExecutingContext.ValueProviderFactories.Count; i++) + for (var i = 0; i < _valueProviderFactories.Count; i++) { - var factory = _resourceExecutingContext.ValueProviderFactories[i]; + var factory = _valueProviderFactories[i]; await factory.CreateValueProviderAsync(factoryContext); } Context.ValueProviders = factoryContext.ValueProviders; diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs index de5b720615..516031ea03 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/BasicTests.cs @@ -350,34 +350,5 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Assert Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } - - [Fact] - public async Task ResourceFilter_CreatesSpecificInputAndOutputFormatters() - { - // Arrange - var input = "{\"fullName\":\"John Doe\"}"; - - // Act - var response = await Client.PostAsync( - "http://localhost/api/ActionUsingSpecificFormatters", - new StringContent(input, Encoding.UTF8, "application/json")); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(input, await response.Content.ReadAsStringAsync()); - - // Make sure it does not affect other actions - //Arrange - input = "{\"FullName\":\"John Doe\"}"; - - // Act - response = await Client.PostAsync( - "http://localhost/api/ActionUsingGlobalFormatters", - new StringContent(input, Encoding.UTF8, "application/json")); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal(input, await response.Content.ReadAsStringAsync()); - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs index 9b0ba5a8fa..5d68855e51 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/FiltersTest.cs @@ -509,58 +509,5 @@ 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_ChangesOutputFormatters_JsonReturned() - { - // Arrange - var input = "{ sampleInt: 10 }"; - var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Json"); - request.Content = new StringContent(input, Encoding.UTF8, "application/json"); - - // Act - var response = await Client.SendAsync(request); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); - Assert.Equal("\"10\"", await response.Content.ReadAsStringAsync()); - } - - [Fact] - public async Task ResourceFilter_ChangesInputFormatters_JsonAccepted() - { - // Arrange - var input = "{ sampleInt: 10 }"; - var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Json"); - request.Content = new StringContent(input, Encoding.UTF8, "application/json"); - - // Act - var response = await Client.SendAsync(request); - - // Assert - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - Assert.Equal("\"10\"", await response.Content.ReadAsStringAsync()); - } - - [Fact] - public async Task ResourceFilter_ChangesInputFormatters_XmlDenied() - { - // Arrange - var input = - "" + - "10" + - ""; - - // There's nothing that can deserialize the body, so the result is UnsupportedMediaType. - var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Json"); - request.Content = new StringContent(input, Encoding.UTF8, "application/xml"); - - // Act - var response = await Client.SendAsync(request); - - // Assert - Assert.Equal(HttpStatusCode.UnsupportedMediaType, response.StatusCode); - } } } \ No newline at end of file diff --git a/test/WebSites/BasicWebSite/Controllers/SpecificFormattersController.cs b/test/WebSites/BasicWebSite/Controllers/SpecificFormattersController.cs deleted file mode 100644 index ce802de203..0000000000 --- a/test/WebSites/BasicWebSite/Controllers/SpecificFormattersController.cs +++ /dev/null @@ -1,86 +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; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; - -namespace BasicWebSite -{ - public class SpecificFormattersController : Controller - { - [HttpPost("api/ActionUsingSpecificFormatters")] - [CamelCaseJsonFormatters] - public IActionResult ActionUsingSpecificFormatters([FromBody] Person person) - { - if (!ModelState.IsValid) - { - return BadRequest(ModelState); - } - - return Ok(person); - } - - [HttpPost("api/ActionUsingGlobalFormatters")] - public IActionResult ActionUsingGlobalFormatters([FromBody] Person person) - { - if (!ModelState.IsValid) - { - return BadRequest(ModelState); - } - - return Ok(person); - } - - public class Person - { - public string FullName { get; set; } - } - - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] - private class CamelCaseJsonFormattersAttribute : Attribute, IResourceFilter, IResultFilter - { - private readonly JsonSerializerSettings _serializerSettings; - - public CamelCaseJsonFormattersAttribute() - { - _serializerSettings = new JsonSerializerSettings(); - _serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - } - - public void OnResourceExecuted(ResourceExecutedContext context) - { - } - - public void OnResourceExecuting(ResourceExecutingContext context) - { - // Do not modify existing json formatters as they would effect all controllers. - // Instead remove and add new formatters which only effects the controllers this - // attribute is decorated on. - context.InputFormatters.RemoveType(); - var loggerFactory = context.HttpContext.RequestServices.GetRequiredService(); - var logger = loggerFactory.CreateLogger(); - context.InputFormatters.Add(new JsonInputFormatter(logger ,_serializerSettings)); - } - - public void OnResultExecuted(ResultExecutedContext context) - { - } - - public void OnResultExecuting(ResultExecutingContext context) - { - var objectResult = context.Result as ObjectResult; - if (objectResult != null) - { - objectResult.Formatters.RemoveType(); - objectResult.Formatters.Add(new JsonOutputFormatter(_serializerSettings)); - } - } - } - } -} diff --git a/test/WebSites/FiltersWebSite/Controllers/JsonOnlyController.cs b/test/WebSites/FiltersWebSite/Controllers/JsonOnlyController.cs deleted file mode 100644 index 5957e233db..0000000000 --- a/test/WebSites/FiltersWebSite/Controllers/JsonOnlyController.cs +++ /dev/null @@ -1,58 +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; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace FiltersWebSite.Controllers -{ - [JsonOnly] - [Route("Json")] - public class JsonOnlyController : Controller - { - [HttpPost] - public string Post([FromBody] DummyClass dummy) - { - return (dummy?.SampleInt ?? 0).ToString(); - } - - private class JsonOnlyAttribute : Attribute, IResultFilter - { - public void OnResourceExecuted(ResourceExecutedContext context) - { - } - - public void OnResourceExecuting(ResourceExecutingContext context) - { - // InputFormatters collection contains JsonInputFormatter and JsonPatchInputFormatter. Picking - // JsonInputFormatter by matching the type exactly rather than using OfType. - var jsonFormatter = context.InputFormatters.OfType() - .Where(t => t.GetType() == typeof(JsonInputFormatter)).FirstOrDefault(); - - context.InputFormatters.Clear(); - context.InputFormatters.Add(jsonFormatter); - } - - public void OnResultExecuted(ResultExecutedContext context) - { - } - - public void OnResultExecuting(ResultExecutingContext context) - { - // Update the output formatter collection to only return JSON. - if (context.Result is ObjectResult) - { - var options = context.HttpContext.RequestServices.GetRequiredService>(); - var jsonFormatter = options.Value.OutputFormatters.OfType().Single(); - var result = (ObjectResult)context.Result; - result.Formatters.Add(jsonFormatter); - } - } - } - } -} \ No newline at end of file