This reverts commit 48261fdada.
This commit is contained in:
parent
3dc14e8136
commit
7da6931209
|
|
@ -77,6 +77,8 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
|
public override System.Threading.Tasks.ValueTask DisposeAsync() { throw null; }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
|
public System.Threading.Tasks.Task DrainBufferAsync(System.IO.Pipelines.PipeWriter destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
||||||
|
[System.Diagnostics.DebuggerStepThroughAttribute]
|
||||||
public System.Threading.Tasks.Task DrainBufferAsync(System.IO.Stream destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
public System.Threading.Tasks.Task DrainBufferAsync(System.IO.Stream destination, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
|
||||||
public override void Flush() { }
|
public override void Flush() { }
|
||||||
public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
|
public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Buffers;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Pipelines;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Internal;
|
using Microsoft.AspNetCore.Internal;
|
||||||
|
|
@ -185,8 +186,25 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
// unspooled content. Copy the FileStream content first when available.
|
// unspooled content. Copy the FileStream content first when available.
|
||||||
if (FileStream != null)
|
if (FileStream != null)
|
||||||
{
|
{
|
||||||
await FileStream.FlushAsync(cancellationToken);
|
// We make a new stream for async reads from disk and async writes to the destination
|
||||||
|
await using var readStream = new FileStream(FileStream.Name, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite, bufferSize: 1, useAsync: true);
|
||||||
|
|
||||||
|
await readStream.CopyToAsync(destination, cancellationToken);
|
||||||
|
|
||||||
|
// This is created with delete on close
|
||||||
|
await FileStream.DisposeAsync();
|
||||||
|
FileStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
await PagedByteBuffer.MoveToAsync(destination, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DrainBufferAsync(PipeWriter destination, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
// When not null, FileStream always has "older" spooled content. The PagedByteBuffer always has "newer"
|
||||||
|
// unspooled content. Copy the FileStream content first when available.
|
||||||
|
if (FileStream != null)
|
||||||
|
{
|
||||||
// We make a new stream for async reads from disk and async writes to the destination
|
// We make a new stream for async reads from disk and async writes to the destination
|
||||||
await using var readStream = new FileStream(FileStream.Name, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite, bufferSize: 1, useAsync: true);
|
await using var readStream = new FileStream(FileStream.Name, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite, bufferSize: 1, useAsync: true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -371,24 +371,6 @@ namespace Microsoft.AspNetCore.WebUtilities
|
||||||
Assert.Equal(0, bufferingStream.Length);
|
Assert.Equal(0, bufferingStream.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task DrainBufferAsync_IncludesContentPossiblyBufferedByFileStream()
|
|
||||||
{
|
|
||||||
// We want to ensure that the FileStream (which has a 1-byte buffer) flushes prior to the other read stream reading input.
|
|
||||||
// Arrange
|
|
||||||
var input = new byte[] { 3, };
|
|
||||||
using var bufferingStream = new FileBufferingWriteStream(0, tempFileDirectoryAccessor: () => TempDirectory);
|
|
||||||
bufferingStream.Write(input, 0, input.Length);
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await bufferingStream.DrainBufferAsync(memoryStream, default);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(input, memoryStream.ToArray());
|
|
||||||
Assert.Equal(0, bufferingStream.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
if (fileBufferingWriteStream != null)
|
if (fileBufferingWriteStream != null)
|
||||||
{
|
{
|
||||||
response.ContentLength = fileBufferingWriteStream.Length;
|
response.ContentLength = fileBufferingWriteStream.Length;
|
||||||
await fileBufferingWriteStream.DrainBufferAsync(response.Body);
|
await fileBufferingWriteStream.DrainBufferAsync(response.BodyWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
if (fileBufferingWriteStream != null)
|
if (fileBufferingWriteStream != null)
|
||||||
{
|
{
|
||||||
response.ContentLength = fileBufferingWriteStream.Length;
|
response.ContentLength = fileBufferingWriteStream.Length;
|
||||||
await fileBufferingWriteStream.DrainBufferAsync(response.Body);
|
await fileBufferingWriteStream.DrainBufferAsync(response.BodyWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -154,17 +154,15 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
Assert.Equal(expected, await response.Content.ReadAsStringAsync());
|
Assert.Equal(expected, await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Fact]
|
||||||
[InlineData(65 * 1024)]
|
public virtual async Task Formatting_LargeObject()
|
||||||
[InlineData(2 * 1024 * 1024)]
|
|
||||||
public virtual async Task Formatting_LargeObject(int size)
|
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedName = "This is long so we can test large objects " + new string('a', size);
|
var expectedName = "This is long so we can test large objects " + new string('a', 1024 * 65);
|
||||||
var expected = $"{{\"id\":10,\"name\":\"{expectedName}\",\"streetName\":null}}";
|
var expected = $"{{\"id\":10,\"name\":\"{expectedName}\",\"streetName\":null}}";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var response = await Client.GetAsync($"/JsonOutputFormatter/{nameof(JsonOutputFormatterController.LargeObjectResult)}/{size}");
|
var response = await Client.GetAsync($"/JsonOutputFormatter/{nameof(JsonOutputFormatterController.LargeObjectResult)}");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,12 @@ namespace FormatterWebSite.Controllers
|
||||||
["Key3"] = null,
|
["Key3"] = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
[HttpGet("{size:int}")]
|
[HttpGet]
|
||||||
public ActionResult<SimpleModel> LargeObjectResult(int size) =>
|
public ActionResult<SimpleModel> LargeObjectResult() =>
|
||||||
new SimpleModel
|
new SimpleModel
|
||||||
{
|
{
|
||||||
Id = 10,
|
Id = 10,
|
||||||
Name = "This is long so we can test large objects " + new string('a', size),
|
Name = "This is long so we can test large objects " + new string('a', 1024 * 65),
|
||||||
};
|
};
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue