[Fixes #3503] Removing formatters on a given type only works on collections in MVC options
This commit is contained in:
parent
a65a6a7cab
commit
982c7abea8
|
|
@ -27,12 +27,12 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="IInputFormatter"/> instances used by model binding.
|
||||
/// </summary>
|
||||
public virtual IList<IInputFormatter> InputFormatters { get; set; }
|
||||
public virtual FormatterCollection<IInputFormatter> InputFormatters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="IOutputFormatter"/> instances used to format the response.
|
||||
/// </summary>
|
||||
public virtual IList<IOutputFormatter> OutputFormatters { get; set; }
|
||||
public virtual FormatterCollection<IOutputFormatter> OutputFormatters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding.
|
||||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
public virtual IList<IModelBinder> ModelBinders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the result of the action to be executed.
|
||||
/// Gets or sets the result of the action to be executed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting <see cref="Result"/> to a non-<c>null</c> value inside a resource filter will
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 System.Collections.ObjectModel;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Formatters
|
||||
|
|
@ -11,6 +12,23 @@ namespace Microsoft.AspNet.Mvc.Formatters
|
|||
/// <typeparam name="TFormatter">The type of formatters in the collection.</typeparam>
|
||||
public class FormatterCollection<TFormatter> : Collection<TFormatter>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FormatterCollection{TFormatter}"/> class that is empty.
|
||||
/// </summary>
|
||||
public FormatterCollection()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FormatterCollection{TFormatter}"/> class
|
||||
/// as a wrapper for the specified list.
|
||||
/// </summary>
|
||||
/// <param name="list">The list that is wrapped by the new collection.</param>
|
||||
public FormatterCollection(IList<TFormatter> list)
|
||||
: base(list)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all formatters of the specified type.
|
||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
|
|||
|
||||
private ResultExecutingContext _resultExecutingContext;
|
||||
private ResultExecutedContext _resultExecutedContext;
|
||||
|
||||
|
||||
public FilterActionInvoker(
|
||||
ActionContext actionContext,
|
||||
IReadOnlyList<IFilterProvider> filterProviders,
|
||||
|
|
@ -334,8 +334,10 @@ namespace Microsoft.AspNet.Mvc.Controllers
|
|||
|
||||
var context = new ResourceExecutingContext(ActionContext, _filters);
|
||||
|
||||
context.InputFormatters = new CopyOnWriteList<IInputFormatter>(_inputFormatters);
|
||||
context.OutputFormatters = new CopyOnWriteList<IOutputFormatter>(_outputFormatters);
|
||||
context.InputFormatters = new FormatterCollection<IInputFormatter>(
|
||||
new CopyOnWriteList<IInputFormatter>(_inputFormatters));
|
||||
context.OutputFormatters = new FormatterCollection<IOutputFormatter>(
|
||||
new CopyOnWriteList<IOutputFormatter>(_outputFormatters));
|
||||
context.ModelBinders = new CopyOnWriteList<IModelBinder>(_modelBinders);
|
||||
context.ValidatorProviders = new CopyOnWriteList<IModelValidatorProvider>(_modelValidatorProviders);
|
||||
context.ValueProviderFactories = new CopyOnWriteList<IValueProviderFactory>(_valueProviderFactories);
|
||||
|
|
@ -411,7 +413,7 @@ namespace Microsoft.AspNet.Mvc.Controllers
|
|||
{
|
||||
// Short-circuited by setting a result.
|
||||
Logger.ResourceFilterShortCircuited(item.Filter);
|
||||
|
||||
|
||||
await InvokeResultAsync(_resourceExecutingContext.Result);
|
||||
|
||||
_resourceExecutedContext = new ResourceExecutedContext(_resourceExecutingContext, _filters)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Net;
|
|||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
|
@ -346,5 +347,34 @@ namespace Microsoft.AspNet.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// 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.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Filters;
|
||||
using Microsoft.AspNet.Mvc.Formatters;
|
||||
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 HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return Ok(person);
|
||||
}
|
||||
|
||||
[HttpPost("api/ActionUsingGlobalFormatters")]
|
||||
public IActionResult ActionUsingGlobalFormatters([FromBody] Person person)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(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
|
||||
{
|
||||
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<JsonInputFormatter>();
|
||||
context.OutputFormatters.RemoveType<JsonOutputFormatter>();
|
||||
|
||||
context.InputFormatters.Add(new JsonInputFormatter(_serializerSettings));
|
||||
context.OutputFormatters.Add(new JsonOutputFormatter(_serializerSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue