Adding Outputformatter in resource filters.

This commit is contained in:
Harsh Gupta 2015-04-07 21:21:17 -07:00
parent f60896bd90
commit 58a5ad2279
20 changed files with 320 additions and 22 deletions

View File

@ -273,12 +273,27 @@ namespace Microsoft.AspNet.Mvc
IEnumerable<IOutputFormatter> formatters = null; IEnumerable<IOutputFormatter> formatters = null;
if (Formatters == null || Formatters.Count == 0) if (Formatters == null || Formatters.Count == 0)
{ {
formatters = context var actionBindingContext = context
.HttpContext .HttpContext
.RequestServices .RequestServices
.GetRequiredService<IOptions<MvcOptions>>() .GetRequiredService<IScopedInstance<ActionBindingContext>>()
.Options .Value;
.OutputFormatters;
// In scenarios where there is a resource filter which directly shortcircuits using an ObjectResult.
// actionBindingContext is not setup yet and is null.
if (actionBindingContext == null)
{
var options = context
.HttpContext
.RequestServices
.GetRequiredService<IOptions<MvcOptions>>()
.Options;
formatters = options.OutputFormatters;
}
else
{
formatters = actionBindingContext.OutputFormatters ?? new List<IOutputFormatter>();
}
} }
else else
{ {

View File

@ -24,6 +24,7 @@ namespace Microsoft.AspNet.Mvc.Core
[NotNull] IControllerFactory controllerFactory, [NotNull] IControllerFactory controllerFactory,
[NotNull] ControllerActionDescriptor descriptor, [NotNull] ControllerActionDescriptor descriptor,
[NotNull] IReadOnlyList<IInputFormatter> inputFormatters, [NotNull] IReadOnlyList<IInputFormatter> inputFormatters,
[NotNull] IReadOnlyList<IOutputFormatter> outputFormatters,
[NotNull] IControllerActionArgumentBinder controllerActionArgumentBinder, [NotNull] IControllerActionArgumentBinder controllerActionArgumentBinder,
[NotNull] IReadOnlyList<IModelBinder> modelBinders, [NotNull] IReadOnlyList<IModelBinder> modelBinders,
[NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, [NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
@ -31,9 +32,10 @@ namespace Microsoft.AspNet.Mvc.Core
[NotNull] IScopedInstance<ActionBindingContext> actionBindingContextAccessor, [NotNull] IScopedInstance<ActionBindingContext> actionBindingContextAccessor,
[NotNull] ITempDataDictionary tempData) [NotNull] ITempDataDictionary tempData)
: base( : base(
actionContext, actionContext,
filterProviders, filterProviders,
inputFormatters, inputFormatters,
outputFormatters,
modelBinders, modelBinders,
modelValidatorProviders, modelValidatorProviders,
valueProviderFactories, valueProviderFactories,

View File

@ -17,6 +17,7 @@ namespace Microsoft.AspNet.Mvc.Core
private readonly IFilterProvider[] _filterProviders; private readonly IFilterProvider[] _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters; private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders; private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders; private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IScopedInstance<ActionBindingContext> _actionBindingContextAccessor; private readonly IScopedInstance<ActionBindingContext> _actionBindingContextAccessor;
@ -34,6 +35,7 @@ namespace Microsoft.AspNet.Mvc.Core
_filterProviders = filterProviders.OrderBy(item => item.Order).ToArray(); _filterProviders = filterProviders.OrderBy(item => item.Order).ToArray();
_argumentBinder = argumentBinder; _argumentBinder = argumentBinder;
_inputFormatters = optionsAccessor.Options.InputFormatters.ToArray(); _inputFormatters = optionsAccessor.Options.InputFormatters.ToArray();
_outputFormatters = optionsAccessor.Options.OutputFormatters.ToArray();
_modelBinders = optionsAccessor.Options.ModelBinders.ToArray(); _modelBinders = optionsAccessor.Options.ModelBinders.ToArray();
_modelValidatorProviders = optionsAccessor.Options.ModelValidatorProviders.ToArray(); _modelValidatorProviders = optionsAccessor.Options.ModelValidatorProviders.ToArray();
_valueProviderFactories = optionsAccessor.Options.ValueProviderFactories.ToArray(); _valueProviderFactories = optionsAccessor.Options.ValueProviderFactories.ToArray();
@ -59,6 +61,7 @@ namespace Microsoft.AspNet.Mvc.Core
_controllerFactory, _controllerFactory,
actionDescriptor, actionDescriptor,
_inputFormatters, _inputFormatters,
_outputFormatters,
_argumentBinder, _argumentBinder,
_modelBinders, _modelBinders,
_modelValidatorProviders, _modelValidatorProviders,

View File

@ -18,6 +18,7 @@ namespace Microsoft.AspNet.Mvc.Core
private readonly IReadOnlyList<IFilterProvider> _filterProviders; private readonly IReadOnlyList<IFilterProvider> _filterProviders;
private readonly IReadOnlyList<IInputFormatter> _inputFormatters; private readonly IReadOnlyList<IInputFormatter> _inputFormatters;
private readonly IReadOnlyList<IModelBinder> _modelBinders; private readonly IReadOnlyList<IModelBinder> _modelBinders;
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders; private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories; private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
@ -43,6 +44,7 @@ namespace Microsoft.AspNet.Mvc.Core
[NotNull] ActionContext actionContext, [NotNull] ActionContext actionContext,
[NotNull] IReadOnlyList<IFilterProvider> filterProviders, [NotNull] IReadOnlyList<IFilterProvider> filterProviders,
[NotNull] IReadOnlyList<IInputFormatter> inputFormatters, [NotNull] IReadOnlyList<IInputFormatter> inputFormatters,
[NotNull] IReadOnlyList<IOutputFormatter> outputFormatters,
[NotNull] IReadOnlyList<IModelBinder> modelBinders, [NotNull] IReadOnlyList<IModelBinder> modelBinders,
[NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, [NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
[NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories, [NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories,
@ -52,6 +54,7 @@ namespace Microsoft.AspNet.Mvc.Core
_filterProviders = filterProviders; _filterProviders = filterProviders;
_inputFormatters = inputFormatters; _inputFormatters = inputFormatters;
_outputFormatters = outputFormatters;
_modelBinders = modelBinders; _modelBinders = modelBinders;
_modelValidatorProviders = modelValidatorProviders; _modelValidatorProviders = modelValidatorProviders;
_valueProviderFactories = valueProviderFactories; _valueProviderFactories = valueProviderFactories;
@ -208,6 +211,7 @@ namespace Microsoft.AspNet.Mvc.Core
var context = new ResourceExecutingContext(ActionContext, _filters); var context = new ResourceExecutingContext(ActionContext, _filters);
context.InputFormatters = new List<IInputFormatter>(_inputFormatters); context.InputFormatters = new List<IInputFormatter>(_inputFormatters);
context.OutputFormatters = new List<IOutputFormatter>(_outputFormatters);
context.ModelBinders = new List<IModelBinder>(_modelBinders); context.ModelBinders = new List<IModelBinder>(_modelBinders);
context.ValidatorProviders = new List<IModelValidatorProvider>(_modelValidatorProviders); context.ValidatorProviders = new List<IModelValidatorProvider>(_modelValidatorProviders);
context.ValueProviderFactories = new List<IValueProviderFactory>(_valueProviderFactories); context.ValueProviderFactories = new List<IValueProviderFactory>(_valueProviderFactories);
@ -417,6 +421,7 @@ namespace Microsoft.AspNet.Mvc.Core
ActionBindingContext = new ActionBindingContext(); ActionBindingContext = new ActionBindingContext();
ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters; ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters;
ActionBindingContext.OutputFormatters = _resourceExecutingContext.OutputFormatters;
ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders); ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders);
ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider( ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider(
_resourceExecutingContext.ValidatorProviders); _resourceExecutingContext.ValidatorProviders);

View File

@ -28,6 +28,11 @@ namespace Microsoft.AspNet.Mvc
/// </summary> /// </summary>
public virtual IList<IInputFormatter> InputFormatters { get; set; } public virtual IList<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; }
/// <summary> /// <summary>
/// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding. /// Gets or sets the list of <see cref="IModelBinder"/> instances used by model binding.
/// </summary> /// </summary>

View File

@ -15,6 +15,8 @@ namespace Microsoft.AspNet.Mvc
public IList<IInputFormatter> InputFormatters { get; set; } public IList<IInputFormatter> InputFormatters { get; set; }
public IList<IOutputFormatter> OutputFormatters { get; set; }
public IModelValidatorProvider ValidatorProvider { get; set; } public IModelValidatorProvider ValidatorProvider { get; set; }
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core;
@ -91,6 +92,7 @@ namespace Microsoft.AspNet.Mvc
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
httpContext.Request.PathBase = new PathString(""); httpContext.Request.PathBase = new PathString("");
httpContext.Response.Body = new MemoryStream(); httpContext.Response.Body = new MemoryStream();
var services = new Mock<IServiceProvider>(); var services = new Mock<IServiceProvider>();
httpContext.RequestServices = services.Object; httpContext.RequestServices = services.Object;
@ -100,6 +102,14 @@ namespace Microsoft.AspNet.Mvc
services.Setup(p => p.GetService(typeof(IOptions<MvcOptions>))) services.Setup(p => p.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor); .Returns(optionsAccessor);
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor
.SetupGet(o => o.Value)
.Returns(new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters });
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockContextAccessor.Object);
return httpContext; return httpContext;
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core;
@ -107,6 +108,15 @@ namespace Microsoft.AspNet.Mvc
httpContext.Setup(o => o.Response) httpContext.Setup(o => o.Response)
.Returns(response); .Returns(response);
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor
.SetupGet(o => o.Value)
.Returns((ActionBindingContext)null);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockContextAccessor.Object);
return httpContext.Object; return httpContext.Object;
} }

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core;
@ -90,8 +91,18 @@ namespace Microsoft.AspNet.Mvc
var optionsAccessor = new MockMvcOptionsAccessor(); var optionsAccessor = new MockMvcOptionsAccessor();
optionsAccessor.Options.OutputFormatters.Add(new StringOutputFormatter()); optionsAccessor.Options.OutputFormatters.Add(new StringOutputFormatter());
optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter()); optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter());
httpContext.Setup(p => p.RequestServices.GetService(typeof(IOptions<MvcOptions>))) httpContext
.Setup(p => p.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor); .Returns(optionsAccessor);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
mockActionBindingContext
.SetupGet(o=> o.Value)
.Returns(new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters });
httpContext
.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
return httpContext.Object; return httpContext.Object;
} }
} }

View File

@ -92,6 +92,16 @@ namespace Microsoft.AspNet.Mvc
optionsAccessor.Options.OutputFormatters.Add(new StringOutputFormatter()); optionsAccessor.Options.OutputFormatters.Add(new StringOutputFormatter());
optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter()); optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter());
optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader; optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader;
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor
.SetupGet(o => o.Value)
.Returns(new ActionBindingContext()
{
OutputFormatters = optionsAccessor.Options.OutputFormatters
});
httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockContextAccessor.Object);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>))) httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor); .Returns(optionsAccessor);

View File

@ -162,6 +162,25 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
Assert.Equal(expectedContentType, httpResponse.ContentType); Assert.Equal(expectedContentType, httpResponse.ContentType);
} }
[Fact]
public async Task ObjectResult_FallsBackOn_FormattersInOptions()
{
// Arrange
var formatter = GetMockFormatter();
var actionContext = CreateMockActionContext(
new[] { formatter.Object },
setupActionBindingContext: false);
// Set the content type property explicitly to a single value.
var result = new ObjectResult("someValue");
// Act
await result.ExecuteResultAsync(actionContext);
// Assert
formatter.Verify(o => o.WriteAsync(It.IsAny<OutputFormatterContext>()));
}
[Fact] [Fact]
public async Task ObjectResult_WithSingleContentType_TheContentTypeIsIgnoredIfTheTypeIsString() public async Task ObjectResult_WithSingleContentType_TheContentTypeIsIgnoredIfTheTypeIsString()
{ {
@ -824,11 +843,11 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
} }
private static ActionContext CreateMockActionContext( private static ActionContext CreateMockActionContext(
HttpResponse response = null, HttpResponse response = null,
string requestAcceptHeader = "application/*", string requestAcceptHeader = "application/*",
string requestContentType = "application/json", string requestContentType = "application/json",
string requestAcceptCharsetHeader = "", string requestAcceptCharsetHeader = "",
bool respectBrowserAcceptHeader = false) bool respectBrowserAcceptHeader = false)
{ {
var formatters = new IOutputFormatter[] { new StringOutputFormatter(), new JsonOutputFormatter() }; var formatters = new IOutputFormatter[] { new StringOutputFormatter(), new JsonOutputFormatter() };
@ -842,12 +861,13 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
} }
private static ActionContext CreateMockActionContext( private static ActionContext CreateMockActionContext(
IEnumerable<IOutputFormatter> outputFormatters, IEnumerable<IOutputFormatter> outputFormatters,
HttpResponse response = null, HttpResponse response = null,
string requestAcceptHeader = "application/*", string requestAcceptHeader = "application/*",
string requestContentType = "application/json", string requestContentType = "application/json",
string requestAcceptCharsetHeader = "", string requestAcceptCharsetHeader = "",
bool respectBrowserAcceptHeader = false) bool respectBrowserAcceptHeader = false,
bool setupActionBindingContext = true)
{ {
var httpContext = new Mock<HttpContext>(); var httpContext = new Mock<HttpContext>();
if (response != null) if (response != null)
@ -872,10 +892,26 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
{ {
optionsAccessor.Options.OutputFormatters.Add(formatter); optionsAccessor.Options.OutputFormatters.Add(formatter);
} }
optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader; optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader;
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>))) httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor); .Returns(optionsAccessor);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
ActionBindingContext bindingContext = null;
if (setupActionBindingContext)
{
bindingContext = new ActionBindingContext { OutputFormatters = outputFormatters.ToList() };
}
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor()); return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
} }

View File

@ -11,7 +11,6 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Metadata;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing; using Microsoft.AspNet.Testing;
@ -2030,13 +2029,13 @@ namespace Microsoft.AspNet.Mvc
filterProvider.SetupGet(fp => fp.Order) filterProvider.SetupGet(fp => fp.Order)
.Returns(DefaultOrder.DefaultFrameworkSortOrder); .Returns(DefaultOrder.DefaultFrameworkSortOrder);
var invoker = new TestControllerActionInvoker( var invoker = new TestControllerActionInvoker(
actionContext, actionContext,
new[] { filterProvider.Object }, new[] { filterProvider.Object },
new MockControllerFactory(this), new MockControllerFactory(this),
actionDescriptor, actionDescriptor,
new InputFormatter[0], new InputFormatter[0],
new IOutputFormatter[0],
Mock.Of<IControllerActionArgumentBinder>(), Mock.Of<IControllerActionArgumentBinder>(),
new IModelBinder[0], new IModelBinder[0],
new IModelValidatorProvider[0], new IModelValidatorProvider[0],
@ -2085,6 +2084,7 @@ namespace Microsoft.AspNet.Mvc
var controllerFactory = new Mock<IControllerFactory>(); var controllerFactory = new Mock<IControllerFactory>();
controllerFactory.Setup(c => c.CreateController(It.IsAny<ActionContext>())) controllerFactory.Setup(c => c.CreateController(It.IsAny<ActionContext>()))
.Returns(new TestController()); .Returns(new TestController());
var metadataProvider = new EmptyModelMetadataProvider(); var metadataProvider = new EmptyModelMetadataProvider();
var invoker = new ControllerActionInvoker( var invoker = new ControllerActionInvoker(
actionContext, actionContext,
@ -2092,6 +2092,7 @@ namespace Microsoft.AspNet.Mvc
controllerFactory.Object, controllerFactory.Object,
actionDescriptor, actionDescriptor,
new IInputFormatter[0], new IInputFormatter[0],
new IOutputFormatter[0],
new DefaultControllerActionArgumentBinder( new DefaultControllerActionArgumentBinder(
metadataProvider, metadataProvider,
new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider), new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider),
@ -2193,6 +2194,7 @@ namespace Microsoft.AspNet.Mvc
MockControllerFactory controllerFactory, MockControllerFactory controllerFactory,
ControllerActionDescriptor descriptor, ControllerActionDescriptor descriptor,
IReadOnlyList<IInputFormatter> inputFormatters, IReadOnlyList<IInputFormatter> inputFormatters,
IReadOnlyList<IOutputFormatter> outputFormatters,
IControllerActionArgumentBinder controllerActionArgumentBinder, IControllerActionArgumentBinder controllerActionArgumentBinder,
IReadOnlyList<IModelBinder> modelBinders, IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders, IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
@ -2205,6 +2207,7 @@ namespace Microsoft.AspNet.Mvc
controllerFactory, controllerFactory,
descriptor, descriptor,
inputFormatters, inputFormatters,
outputFormatters,
controllerActionArgumentBinder, controllerActionArgumentBinder,
modelBinders, modelBinders,
modelValidatorProviders, modelValidatorProviders,

View File

@ -588,6 +588,71 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal("Throwing Exception Filter", await response.Content.ReadAsStringAsync()); Assert.Equal("Throwing Exception Filter", await response.Content.ReadAsStringAsync());
} }
[Fact]
public async Task ResourceFilter_ShortCircuitsUsingObjectResult_UsesOptions()
{
// Arrange
var input = "{ sampleInt: 10 }";
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/ResourceFilter/Post");
request.Content = new StringContent(input, Encoding.UTF8, "application/json");
// Act
var response = await client.SendAsync(request);
// Assert
// Uses formatters from options.
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// Notice this has been formatted using StringOutputFormatter and not JsonOutputFormatter.
Assert.Equal("someValue", await response.Content.ReadAsStringAsync());
}
[Fact]
public async Task ResourceFilter_ShortCircuitsUsingObjectResult_WithJsonFormatter_ReturnsResponse()
{
// Arrange
var input = "{ sampleInt: 10 }";
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/ResourceFilter/Get");
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("\"someValue\"", await response.Content.ReadAsStringAsync());
}
[Fact]
public async Task ResourceFilter_ChangesOutputFormatters_JsonReturned()
{
// Arrange
var input = "{ sampleInt: 10 }";
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
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] [Fact]
public async Task ResourceFilter_ChangesInputFormatters_JsonAccepted() public async Task ResourceFilter_ChangesInputFormatters_JsonAccepted()
{ {
@ -605,7 +670,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("10", await response.Content.ReadAsStringAsync()); Assert.Equal("\"10\"", await response.Content.ReadAsStringAsync());
} }
[Fact] [Fact]
@ -630,7 +695,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("0", await response.Content.ReadAsStringAsync()); Assert.Equal("\"0\"", await response.Content.ReadAsStringAsync());
} }
} }
} }

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities; using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -72,6 +73,15 @@ namespace System.Web.Http
var optionsAccessor = new Mock<IOptions<MvcOptions>>(); var optionsAccessor = new Mock<IOptions<MvcOptions>>();
optionsAccessor.SetupGet(o => o.Options) optionsAccessor.SetupGet(o => o.Options)
.Returns(options); .Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>))) services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object); .Returns(optionsAccessor.Object);

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities; using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -73,6 +74,15 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options) optionsAccessor.SetupGet(o => o.Options)
.Returns(options); .Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>))) services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object); .Returns(optionsAccessor.Object);

View File

@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities; using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -86,6 +87,16 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options) optionsAccessor.SetupGet(o => o.Options)
.Returns(options); .Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>))) services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object); .Returns(optionsAccessor.Object);

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Http.Core; using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -74,6 +75,15 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options) optionsAccessor.SetupGet(o => o.Options)
.Returns(options); .Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>))) services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object); .Returns(optionsAccessor.Object);

View File

@ -8,6 +8,7 @@ using Microsoft.AspNet.Http.Core;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.WebUtilities; using Microsoft.AspNet.WebUtilities;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel; using Microsoft.Framework.OptionsModel;
using Moq; using Moq;
using Xunit; using Xunit;
@ -47,6 +48,15 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options) optionsAccessor.SetupGet(o => o.Options)
.Returns(options); .Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>))) services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor.Object); .Returns(optionsAccessor.Object);

View File

@ -32,6 +32,11 @@ namespace FiltersWebSite.Controllers
context.InputFormatters.Clear(); context.InputFormatters.Clear();
context.InputFormatters.Add(jsonFormatter); context.InputFormatters.Add(jsonFormatter);
// Update the output formatter collection to only return JSON.
var jsonOutputFormatter = context.OutputFormatters.OfType<JsonOutputFormatter>().Single();
context.OutputFormatters.Clear();
context.OutputFormatters.Add(jsonOutputFormatter);
} }
} }
} }

View File

@ -0,0 +1,65 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Mvc;
namespace FiltersWebSite.Controllers
{
[Route("ResourceFilter/[action]")]
public class ResourceFilterController : Controller
{
[HttpPost]
[ShortCircuitWithFormatter]
public string Get()
{
return "NeverGetsExecuted";
}
[HttpPost]
[ShortCircuit]
public string Post()
{
return "NeverGetsExecuted";
}
private class ShortCircuitWithFormatterAttribute : Attribute, IResourceFilter
{
private IOutputFormatter[] _formatters;
public ShortCircuitWithFormatterAttribute()
{
_formatters = new IOutputFormatter[] { new JsonOutputFormatter() };
}
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
var result = new ObjectResult("someValue");
foreach (var formatter in _formatters)
{
result.Formatters.Add(formatter);
}
context.Result = result;
}
}
private class ShortCircuitAttribute : Attribute, IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
// ShortCircuit.
context.Result = new ObjectResult("someValue");
}
}
}
}