diff --git a/samples/FormatFilterSample.Web/Startup.cs b/samples/FormatFilterSample.Web/Startup.cs
index 7a5dee35d9..08948b2b1c 100644
--- a/samples/FormatFilterSample.Web/Startup.cs
+++ b/samples/FormatFilterSample.Web/Startup.cs
@@ -15,7 +15,7 @@ namespace FormatFilterSample.Web
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
- services.AddMvc(options =>
+ var mvcBuilder = services.AddMvc(options =>
{
var formatFilter = new FormatFilterAttribute();
options.Filters.Add(formatFilter);
@@ -28,6 +28,8 @@ namespace FormatFilterSample.Web
"custom",
MediaTypeHeaderValue.Parse("application/custom"));
});
+
+ mvcBuilder.AddXmlDataContractSerializerFormatters();
}
public void Configure(IApplicationBuilder app)
diff --git a/samples/FormatFilterSample.Web/project.json b/samples/FormatFilterSample.Web/project.json
index cfa331229d..c5937d7924 100644
--- a/samples/FormatFilterSample.Web/project.json
+++ b/samples/FormatFilterSample.Web/project.json
@@ -7,6 +7,7 @@
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-*",
+ "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-*",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*"
},
"frameworks": {
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/FormatFilter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/FormatFilter.cs
index c067ff6179..d014a93764 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/FormatFilter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/FormatFilter.cs
@@ -122,12 +122,22 @@ namespace Microsoft.AspNet.Mvc.Formatters
}
var objectResult = context.Result as ObjectResult;
- if (objectResult != null)
+ if (objectResult == null)
{
- var contentType = _options.FormatterMappings.GetMediaTypeMappingForFormat(format);
- objectResult.ContentTypes.Clear();
- objectResult.ContentTypes.Add(contentType);
+ return;
}
+
+ // If the action sets a single content type, then its takes precedence over the user
+ // supplied content type based on format mapping.
+ if ((objectResult.ContentTypes != null && objectResult.ContentTypes.Count == 1) ||
+ !string.IsNullOrEmpty(context.HttpContext.Response.ContentType))
+ {
+ return;
+ }
+
+ var contentType = _options.FormatterMappings.GetMediaTypeMappingForFormat(format);
+ objectResult.ContentTypes.Clear();
+ objectResult.ContentTypes.Add(contentType);
}
///
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FormatFilterTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FormatFilterTest.cs
index f86ce95b37..ae39bbb995 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FormatFilterTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FormatFilterTest.cs
@@ -60,12 +60,13 @@ namespace Microsoft.AspNet.Mvc.Formatters
{
// If the format is present in both route and query data, the one in route data wins
- // Arrange
+ // Arrange
var mediaType = MediaTypeHeaderValue.Parse("application/json");
var mockObjects = new MockObjects("json", FormatSource.RouteData);
var httpContext = new Mock();
+ httpContext.Setup(c => c.Response).Returns(new Mock().Object);
- // Query contains xml
+ // Query contains xml
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(true);
httpContext.Setup(c => c.Request.Query["format"]).Returns("xml");
@@ -106,7 +107,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
FormatSource place,
string contentType)
{
- // Arrange
+ // Arrange
var mediaType = MediaTypeHeaderValue.Parse(contentType);
var mockObjects = new MockObjects(format, place);
@@ -226,7 +227,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
// Act
filter.OnResourceExecuting(resourceExecutingContext);
- // Assert
+ // Assert
var actionResult = resourceExecutingContext.Result;
Assert.IsType(actionResult);
}
@@ -298,6 +299,73 @@ namespace Microsoft.AspNet.Mvc.Formatters
Assert.Equal(expected, filter.GetFormat(context));
}
+ [Fact]
+ public void FormatFilter_ExplicitContentType_SetOnObjectResult_TakesPrecedence()
+ {
+ // Arrange
+ var mediaType = MediaTypeHeaderValue.Parse("application/foo");
+ var mockObjects = new MockObjects("json", FormatSource.QueryData);
+ var httpContext = new Mock();
+ httpContext.Setup(c => c.Response).Returns(new Mock().Object);
+ httpContext.Setup(c => c.Request.Query["format"]).Returns("json");
+ var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
+ var objectResult = new ObjectResult("Hello!");
+ objectResult.ContentTypes.Add(new MediaTypeHeaderValue("application/foo"));
+ var resultExecutingContext = new ResultExecutingContext(
+ actionContext,
+ new IFilterMetadata[] { },
+ objectResult,
+ controller: new object());
+
+ var resourceExecutingContext = new ResourceExecutingContext(
+ actionContext,
+ new IFilterMetadata[] { });
+
+ var filter = new FormatFilter(mockObjects.OptionsManager);
+
+ // Act
+ filter.OnResourceExecuting(resourceExecutingContext);
+ filter.OnResultExecuting(resultExecutingContext);
+
+ // Assert
+ var result = Assert.IsType(resultExecutingContext.Result);
+ Assert.Equal(1, result.ContentTypes.Count);
+ AssertMediaTypesEqual(mediaType, result.ContentTypes[0]);
+ }
+
+ [Fact]
+ public void FormatFilter_ExplicitContentType_SetOnResponse_TakesPrecedence()
+ {
+ // Arrange
+ var mediaType = MediaTypeHeaderValue.Parse("application/foo");
+ var mockObjects = new MockObjects("json", FormatSource.QueryData);
+ var response = new Mock();
+ response.Setup(r => r.ContentType).Returns("application/foo");
+ var httpContext = new Mock();
+ httpContext.Setup(c => c.Response).Returns(response.Object);
+ httpContext.Setup(c => c.Request.Query["format"]).Returns("json");
+ var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
+ var resultExecutingContext = new ResultExecutingContext(
+ actionContext,
+ new IFilterMetadata[] { },
+ new ObjectResult("Hello!"),
+ controller: new object());
+
+ var resourceExecutingContext = new ResourceExecutingContext(
+ actionContext,
+ new IFilterMetadata[] { });
+
+ var filter = new FormatFilter(mockObjects.OptionsManager);
+
+ // Act
+ filter.OnResourceExecuting(resourceExecutingContext);
+ filter.OnResultExecuting(resultExecutingContext);
+
+ // Assert
+ var result = Assert.IsType(resultExecutingContext.Result);
+ Assert.Equal(0, result.ContentTypes.Count);
+ }
+
private static void AssertMediaTypesEqual(
MediaTypeHeaderValue expectedMediaType,
MediaTypeHeaderValue actualMediaType)
@@ -326,6 +394,7 @@ namespace Microsoft.AspNet.Mvc.Formatters
{
var httpContext = new Mock();
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(false);
+ httpContext.Setup(c => c.Response).Returns(new Mock().Object);
MockHttpContext = httpContext.Object;
Initialize(httpContext, format, place);