diff --git a/src/Microsoft.AspNet.Mvc.Core/HttpResponseStreamWriter.cs b/src/Microsoft.AspNet.Mvc.Core/HttpResponseStreamWriter.cs
index 25b197d48d..c195bbb289 100644
--- a/src/Microsoft.AspNet.Mvc.Core/HttpResponseStreamWriter.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/HttpResponseStreamWriter.cs
@@ -15,7 +15,10 @@ namespace Microsoft.AspNet.Mvc
///
public class HttpResponseStreamWriter : TextWriter
{
- private const int DefaultBufferSize = 1024;
+ ///
+ /// Default buffer size.
+ ///
+ public const int DefaultBufferSize = 1024;
private readonly Stream _stream;
private Encoder _encoder;
private byte[] _byteBuffer;
diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs
index 6b0536d9e4..43036f9765 100644
--- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs
+++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/ViewExecutor.cs
@@ -62,6 +62,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
htmlHelperOptions);
await view.RenderAsync(viewContext);
+ // Invoke FlushAsync to ensure any buffered content is asynchronously written to the underlying
+ // response. In the absence of this line, the buffer gets synchronously written to the response
+ // as part of the Dispose which has a perf impact.
+ await writer.FlushAsync();
}
}
}
diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs
index 5fec6b2aa0..3dec9fd8f2 100644
--- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs
+++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/ViewExecutorTest.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
@@ -89,7 +90,6 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
view.Setup(v => v.RenderAsync(It.IsAny()))
.Callback((ViewContext v) =>
{
- view.ToString();
v.Writer.Write("abcd");
})
.Returns(Task.FromResult(0));
@@ -99,9 +99,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
context.Response.Body = memoryStream;
context.Response.ContentType = responseContentType;
- var actionContext = new ActionContext(context,
- new RouteData(),
- new ActionDescriptor());
+ var actionContext = new ActionContext(
+ context,
+ new RouteData(),
+ new ActionDescriptor());
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
// Act
@@ -135,9 +136,10 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
var memoryStream = new MemoryStream();
context.Response.Body = memoryStream;
- var actionContext = new ActionContext(context,
- new RouteData(),
- new ActionDescriptor());
+ var actionContext = new ActionContext(
+ context,
+ new RouteData(),
+ new ActionDescriptor());
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
// Act
@@ -153,5 +155,45 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
// Assert
Assert.Equal(expectedLength, memoryStream.Length);
}
+
+ [Theory]
+ [InlineData(HttpResponseStreamWriter.DefaultBufferSize - 1)]
+ [InlineData(HttpResponseStreamWriter.DefaultBufferSize + 1)]
+ [InlineData(2 * HttpResponseStreamWriter.DefaultBufferSize + 4)]
+ public async Task ExecuteAsync_AsynchronouslyFlushesToTheResponseStream_PriorToDispose(int writeLength)
+ {
+ // Arrange
+ var view = new Mock();
+ view.Setup(v => v.RenderAsync(It.IsAny()))
+ .Returns((ViewContext v) =>
+ Task.Run(async () =>
+ {
+ var text = new string('a', writeLength);
+ await v.Writer.WriteAsync(text);
+ }));
+
+ var context = new DefaultHttpContext();
+ var stream = new Mock();
+ context.Response.Body = stream.Object;
+
+ var actionContext = new ActionContext(
+ context,
+ new RouteData(),
+ new ActionDescriptor());
+ var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider());
+
+ // Act
+ await ViewExecutor.ExecuteAsync(
+ view.Object,
+ actionContext,
+ viewData,
+ Mock.Of(),
+ new HtmlHelperOptions(),
+ ViewExecutor.DefaultContentType);
+
+ // Assert
+ stream.Verify(s => s.FlushAsync(It.IsAny()), Times.Once());
+ stream.Verify(s => s.Write(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never());
+ }
}
}
\ No newline at end of file