diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/NoContentFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNoContentOutputFormatter.cs
similarity index 95%
rename from src/Microsoft.AspNet.Mvc.Core/Formatters/NoContentFormatter.cs
rename to src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNoContentOutputFormatter.cs
index 5d2ab6e833..2416f32979 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/NoContentFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNoContentOutputFormatter.cs
@@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc
///
/// Sets the status code to 204 if the content is null.
///
- public class NoContentFormatter : IOutputFormatter
+ public class HttpNoContentOutputFormatter : IOutputFormatter
{
public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
{
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNotAcceptableOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNotAcceptableOutputFormatter.cs
new file mode 100644
index 0000000000..556585490f
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/HttpNotAcceptableOutputFormatter.cs
@@ -0,0 +1,39 @@
+// 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.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// A formatter which does not have a supported content type and selects itself if no content type is passed to it.
+ /// Sets the status code to 406 if selected.
+ ///
+ public class HttpNotAcceptableOutputFormatter : IOutputFormatter
+ {
+ ///
+ public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
+ {
+ return contentType == null;
+ }
+
+ ///
+ public IReadOnlyList GetSupportedContentTypes(Type declaredType,
+ Type runtimeType,
+ MediaTypeHeaderValue contentType)
+ {
+ return null;
+ }
+
+ ///
+ public Task WriteAsync(OutputFormatterContext context)
+ {
+ var response = context.ActionContext.HttpContext.Response;
+ response.StatusCode = 406;
+ return Task.FromResult(true);
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
index e52b291438..3fced5aeb9 100644
--- a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
@@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc
options.ModelBinders.Add(new ComplexModelDtoModelBinder());
// Set up default output formatters.
- options.OutputFormatters.Add(new NoContentFormatter());
+ options.OutputFormatters.Add(new HttpNoContentOutputFormatter());
options.OutputFormatters.Add(new TextPlainFormatter());
options.OutputFormatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(),
indent: false));
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs
index 2de4f9b5bb..df04df1908 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs
@@ -275,18 +275,23 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
}
[Theory]
- [InlineData("", 2)]
- [InlineData(null, 2)]
- [InlineData("application/xml", 3)]
- [InlineData("application/custom", 3)]
- [InlineData("application/xml;q=1, application/custom;q=0.8", 4)]
+ [InlineData("")]
+ [InlineData(null)]
+ [InlineData("application/xml")]
+ [InlineData("application/custom")]
+ [InlineData("application/xml;q=1, application/custom;q=0.8")]
public void SelectFormatter_WithNoMatchingAcceptHeadersAndRequestContentType_PicksFormatterBasedOnObjectType
- (string acceptHeader, int attemptedCountForCanWrite)
+ (string acceptHeader)
{
// For no accept headers,
// can write is called twice once for the request media type and once for the type match pass.
// For each additional accept header, it is called once.
// Arrange
+ var acceptHeaderCollection = string.IsNullOrEmpty(acceptHeader) ?
+ null :
+ acceptHeader?.Split(',')
+ .Select(header => MediaTypeWithQualityHeaderValue.Parse(header))
+ .ToArray();
var stream = new MemoryStream();
var httpResponse = new Mock();
httpResponse.SetupProperty(o => o.ContentType);
@@ -295,15 +300,10 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
var actionContext = CreateMockActionContext(httpResponse.Object,
requestAcceptHeader: acceptHeader,
requestContentType: "application/xml");
+ var requestContentType = MediaTypeHeaderValue.Parse("application/xml");
var input = "testInput";
var result = new ObjectResult(input);
-
- // Set more than one formatters. The test output formatter throws on write.
- result.Formatters = new List
- {
- new CannotWriteFormatter(),
- new CountingFormatter(),
- };
+ var mockCountingFormatter = new Mock();
var context = new OutputFormatterContext()
{
@@ -311,13 +311,37 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
Object = input,
DeclaredType = typeof(string)
};
+ var mockCountingSupportedContentType = MediaTypeHeaderValue.Parse("application/text");
+ mockCountingFormatter.Setup(o => o.CanWriteResult(context,
+ It.IsNotIn(mockCountingSupportedContentType)))
+ .Returns(false);
+ mockCountingFormatter.Setup(o => o.CanWriteResult(context, mockCountingSupportedContentType))
+ .Returns(true);
+
+ mockCountingFormatter.Setup(o => o.GetSupportedContentTypes(context.DeclaredType,
+ input.GetType(),
+ It.IsAny()))
+ .Returns(new List { mockCountingSupportedContentType });
+
+ // Set more than one formatters. The test output formatter throws on write.
+ result.Formatters = new List
+ {
+ new CannotWriteFormatter(),
+ mockCountingFormatter.Object,
+ };
// Act
var formatter = result.SelectFormatter(context, result.Formatters);
// Assert
- var countingFormatter = Assert.IsType(formatter);
- Assert.Equal(attemptedCountForCanWrite, countingFormatter.GetCanWriteCallCount());
+ Assert.Equal(mockCountingFormatter.Object, formatter);
+ mockCountingFormatter.Verify(v => v.CanWriteResult(context,
+ mockCountingSupportedContentType),
+ Times.Once());
+ var callCount = (acceptHeaderCollection == null ? 0 : acceptHeaderCollection.Count()) + 1;
+ mockCountingFormatter.Verify(v => v.CanWriteResult(context,
+ It.IsNotIn(mockCountingSupportedContentType)),
+ Times.Exactly(callCount));
}
[Fact]
@@ -507,42 +531,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
return serviceCollection.BuildServiceProvider();
}
- public class CountingFormatter : OutputFormatter
- {
- private int _canWriteCallsCount = 0;
-
- public CountingFormatter()
- {
- SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/plain"));
- SupportedEncodings.Add(Encoding.GetEncoding("utf-8"));
- }
-
- public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
- {
- _canWriteCallsCount++;
- if (base.CanWriteResult(context, contentType))
- {
- var actionReturnString = context.Object as string;
- if (actionReturnString != null)
- {
- return true;
- }
- }
-
- return false;
- }
-
- public int GetCanWriteCallCount()
- {
- return _canWriteCallsCount;
- }
-
- public override Task WriteResponseBodyAsync(OutputFormatterContext context)
- {
- throw new NotImplementedException();
- }
- }
-
public class CannotWriteFormatter : IOutputFormatter
{
public virtual bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs
index 899190f4ff..0210e3fb55 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs
@@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Mvc.Test
ActionContext = null,
};
var contetType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null;
- var formatter = new NoContentFormatter();
+ var formatter = new HttpNoContentOutputFormatter();
// Act
var actualCanWriteResult = formatter.CanWriteResult(formatterContext, contetType);
@@ -71,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.Test
ActionContext = new ActionContext(defaultHttpContext, new RouteData(), new ActionDescriptor())
};
- var formatter = new NoContentFormatter();
+ var formatter = new HttpNoContentOutputFormatter();
// Act
await formatter.WriteAsync(formatterContext);
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
index a33a09ada6..b1fd58cc6f 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
@@ -3,7 +3,7 @@
using System;
using System.Net;
-using System.Net.Http.Headers;
+using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
diff --git a/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs b/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
index 062ccc50b4..823d541ab5 100644
--- a/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
@@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc
// Assert
Assert.Equal(5, mvcOptions.OutputFormatters.Count);
- Assert.IsType(mvcOptions.OutputFormatters[0].Instance);
+ Assert.IsType(mvcOptions.OutputFormatters[0].Instance);
Assert.IsType(mvcOptions.OutputFormatters[1].Instance);
Assert.IsType(mvcOptions.OutputFormatters[2].Instance);
Assert.IsType(mvcOptions.OutputFormatters[3].Instance);
diff --git a/test/WebSites/ConnegWebSite/Controllers/FallbackOnTypeBasedMatchController.cs b/test/WebSites/ConnegWebSite/Controllers/FallbackOnTypeBasedMatchController.cs
index 8e233e0ce5..773f01edcc 100644
--- a/test/WebSites/ConnegWebSite/Controllers/FallbackOnTypeBasedMatchController.cs
+++ b/test/WebSites/ConnegWebSite/Controllers/FallbackOnTypeBasedMatchController.cs
@@ -47,7 +47,7 @@ namespace ConnegWebsite
public IActionResult OverrideTheFallback_UsingCustomFormatters(int input)
{
var objectResult = new ObjectResult(input);
- objectResult.Formatters.Add(new StopIfNoMatchOutputFormatter());
+ objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
objectResult.Formatters.Add(new PlainTextFormatter());
objectResult.Formatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), false));
return objectResult;
@@ -57,7 +57,7 @@ namespace ConnegWebsite
{
var objectResult = new ObjectResult(input);
var formattersProvider = ActionContext.HttpContext.RequestServices.GetService();
- objectResult.Formatters.Add(new StopIfNoMatchOutputFormatter());
+ objectResult.Formatters.Add(new HttpNotAcceptableOutputFormatter());
foreach (var formatter in formattersProvider.OutputFormatters)
{
objectResult.Formatters.Add(formatter);
@@ -65,26 +65,5 @@ namespace ConnegWebsite
return objectResult;
}
-
- public class StopIfNoMatchOutputFormatter : IOutputFormatter
- {
- // Select if no Registered content type.
- public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
- {
- return contentType == null;
- }
-
- public IReadOnlyList GetSupportedContentTypes(Type declaredType, Type runtimeType, MediaTypeHeaderValue contentType)
- {
- return null;
- }
-
- public Task WriteAsync(OutputFormatterContext context)
- {
- var response = context.ActionContext.HttpContext.Response;
- response.StatusCode = 406;
- return Task.FromResult(true);
- }
- }
}
}
\ No newline at end of file