diff --git a/samples/MvcSample.Web/HomeController.cs b/samples/MvcSample.Web/HomeController.cs
index a7f8251811..343d2a0f84 100644
--- a/samples/MvcSample.Web/HomeController.cs
+++ b/samples/MvcSample.Web/HomeController.cs
@@ -97,7 +97,7 @@ namespace MvcSample.Web
Context.Response.WriteAsync("Hello World raw");
}
- [Produces("application/json", "application/custom", "text/json", Type = typeof(User))]
+ [Produces("application/json", "application/xml", "application/custom", "text/json", Type = typeof(User))]
public object ReturnUser()
{
return CreateUser();
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/DelegatingStream.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/DelegatingStream.cs
index afc27c9430..46ae6154e8 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/DelegatingStream.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/DelegatingStream.cs
@@ -18,14 +18,17 @@ namespace Microsoft.AspNet.Mvc
private readonly Stream _innerStream;
///
- /// Initializes a new object of DelegatingStream
+ /// Initializes a new .
///
- /// The stream on which should not be closed
+ /// The stream which should not be closed or flushed.
public DelegatingStream([NotNull] Stream innerStream)
{
_innerStream = innerStream;
}
+ ///
+ /// The inner stream this object delegates to.
+ ///
protected Stream InnerStream
{
get { return _innerStream; }
@@ -122,7 +125,7 @@ namespace Microsoft.AspNet.Mvc
///
public override void Flush()
{
- _innerStream.Flush();
+ // Do nothing, we want to explicitly avoid flush because it turns on Chunked encoding.
}
///
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonOutputFormatter.cs
index edd413d9ce..c29fe2f3ef 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonOutputFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonOutputFormatter.cs
@@ -46,11 +46,6 @@ namespace Microsoft.AspNet.Mvc
{
var jsonSerializer = CreateJsonSerializer();
jsonSerializer.Serialize(jsonWriter, value);
-
- // We're explicitly calling flush here to simplify the debugging experience because the
- // underlying TextWriter might be long-lived. If this method ends up being called repeatedly
- // for a request, we should revisit.
- jsonWriter.Flush();
}
}
@@ -77,7 +72,9 @@ namespace Microsoft.AspNet.Mvc
{
var response = context.ActionContext.HttpContext.Response;
var selectedEncoding = context.SelectedEncoding;
- using (var writer = new StreamWriter(response.Body, selectedEncoding, 1024, leaveOpen: true))
+
+ using (var delegatingStream = new DelegatingStream(response.Body))
+ using (var writer = new StreamWriter(delegatingStream, selectedEncoding, 1024, leaveOpen: true))
{
WriteObject(writer, context.Object);
}
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs
index c3b0708dc7..cc6f2d8efb 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs
@@ -75,7 +75,8 @@ namespace Microsoft.AspNet.Mvc
/// The type of the object to be serialized.
public virtual Type GetObjectType([NotNull] OutputFormatterContext context)
{
- if (context.DeclaredType == null)
+ if (context.DeclaredType == null ||
+ context.DeclaredType == typeof(object))
{
if (context.Object != null)
{
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs
index 02af1d6b6a..0ee3ea2cde 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs
@@ -61,11 +61,13 @@ namespace Microsoft.AspNet.Mvc
///
public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context)
{
- var response = context.ActionContext.HttpContext.Response;
-
var tempWriterSettings = WriterSettings.Clone();
tempWriterSettings.Encoding = context.SelectedEncoding;
- using (var xmlWriter = CreateXmlWriter(response.Body, tempWriterSettings))
+
+ var innerStream = context.ActionContext.HttpContext.Response.Body;
+
+ using (var outputStream = new DelegatingStream(innerStream))
+ using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings))
{
var dataContractSerializer = (DataContractSerializer)CreateSerializer(GetObjectType(context));
dataContractSerializer.WriteObject(xmlWriter, context.Object);
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs
index 81a74ea247..99bae29710 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs
@@ -61,7 +61,11 @@ namespace Microsoft.AspNet.Mvc
var tempWriterSettings = WriterSettings.Clone();
tempWriterSettings.Encoding = context.SelectedEncoding;
- using (var xmlWriter = CreateXmlWriter(response.Body, tempWriterSettings))
+
+ var innerStream = context.ActionContext.HttpContext.Response.Body;
+
+ using (var outputStream = new DelegatingStream(innerStream))
+ using (var xmlWriter = CreateXmlWriter(outputStream, tempWriterSettings))
{
var xmlSerializer = (XmlSerializer)CreateSerializer(GetObjectType(context));
xmlSerializer.Serialize(xmlWriter, context.Object);
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/DelegatingStreamTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/DelegatingStreamTests.cs
index 334fea6dd6..d3abd30fb3 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/DelegatingStreamTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/DelegatingStreamTests.cs
@@ -3,6 +3,10 @@
#if NET45
using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Mvc.Core;
+using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc
@@ -36,6 +40,52 @@ namespace Microsoft.AspNet.Mvc
// Assert
Assert.True(innerStream.CanRead);
}
+
+ [Fact]
+ public void InnerStreamIsNotFlushedOnDispose()
+ {
+ var stream = FlushReportingStream.GetThrowingStream();
+ var delegatingStream = new DelegatingStream(stream);
+
+ // Act & Assert
+ delegatingStream.Dispose();
+ }
+
+ [Fact]
+ public void InnerStreamIsNotFlushedOnClose()
+ {
+ // Arrange
+ var stream = FlushReportingStream.GetThrowingStream();
+
+ var delegatingStream = new DelegatingStream(stream);
+
+ // Act & Assert
+ delegatingStream.Close();
+ }
+
+ [Fact]
+ public void InnerStreamIsNotFlushedOnFlush()
+ {
+ // Arrange
+ var stream = FlushReportingStream.GetThrowingStream();
+
+ var delegatingStream = new DelegatingStream(stream);
+
+ // Act & Assert
+ delegatingStream.Flush();
+ }
+
+ [Fact]
+ public async Task InnerStreamIsNotFlushedOnFlushAsync()
+ {
+ // Arrange
+ var stream = FlushReportingStream.GetThrowingStream();
+
+ var delegatingStream = new DelegatingStream(stream);
+
+ // Act & Assert
+ await delegatingStream.FlushAsync();
+ }
}
}
#endif
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FlushReportingStream.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FlushReportingStream.cs
new file mode 100644
index 0000000000..6a1c04e972
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/FlushReportingStream.cs
@@ -0,0 +1,18 @@
+using System.IO;
+using System.Threading;
+using Moq;
+
+namespace Microsoft.AspNet.Mvc.Core
+{
+ public static class FlushReportingStream
+ {
+ public static Stream GetThrowingStream()
+ {
+ var mock = new Mock();
+ mock.Verify(m => m.Flush(), Times.Never());
+ mock.Verify(m => m.FlushAsync(It.IsAny()), Times.Never());
+
+ return mock.Object;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs
index 21ed42dd72..1b23830e2a 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs
@@ -182,6 +182,21 @@ namespace Microsoft.AspNet.Mvc.Core
Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
}
+ [Fact]
+ public async Task XmlSerializerOutputFormatterDoesntFlushOutputStream()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlDataContractSerializerOutputFormatter();
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ var response = outputFormatterContext.ActionContext.HttpContext.Response;
+ response.Body = FlushReportingStream.GetThrowingStream();
+
+ // Act & Assert
+ await formatter.WriteAsync(outputFormatterContext);
+ }
+
[Fact]
public void XmlDataContractSerializer_CanWriteResult_ReturnsTrue_ForWritableType()
{
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs
index 75b2a698f3..941936968d 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
@@ -199,6 +200,21 @@ namespace Microsoft.AspNet.Mvc.Core
Assert.True(formatter.CanWriteResult(outputFormatterContext, MediaTypeHeaderValue.Parse("application/xml")));
}
+ [Fact]
+ public async Task XmlSerializerOutputFormatterDoesntFlushOutputStream()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlSerializerOutputFormatter();
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ var response = outputFormatterContext.ActionContext.HttpContext.Response;
+ response.Body = FlushReportingStream.GetThrowingStream();
+
+ // Act & Assert
+ await formatter.WriteAsync(outputFormatterContext);
+ }
+
private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType,
string contentType = "application/xml; charset=utf-8")
{