| File: Rendering\Buffering\BufferedTextWriter.cs | Web Access |
| Project: src\aspnetcore\src\Components\Endpoints\src\Microsoft.AspNetCore.Components.Endpoints.csproj (Microsoft.AspNetCore.Components.Endpoints) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Text; namespace Microsoft.AspNetCore.Components.Endpoints.Rendering; internal class BufferedTextWriter : TextWriter { private const int PageSize = 256; private readonly TextWriter _underlying; private readonly StringBuilder _charArraySegmentBuilder = new(); private TextChunkListBuilder _currentOutput; private TextChunkListBuilder? _previousOutput; private Task _currentFlushAsyncTask = Task.CompletedTask; public BufferedTextWriter(TextWriter underlying) { _underlying = underlying; _currentOutput = new(PageSize); } public override Encoding Encoding => Encoding.UTF8; public override void Write(char value) => _currentOutput.Add(new TextChunk(value)); public override void Write(char[] buffer, int index, int count) => _currentOutput.Add(new TextChunk(new ArraySegment<char>(buffer, index, count), _charArraySegmentBuilder)); public override void Write(string? value) { if (value is not null) { _currentOutput.Add(new TextChunk(value)); } } public override void Write(int value) => _currentOutput.Add(new TextChunk(value)); public override void Flush() => throw new NotSupportedException(); public override Task FlushAsync() { _currentFlushAsyncTask = FlushAsyncCore(_currentFlushAsyncTask); return _currentFlushAsyncTask; } private async Task FlushAsyncCore(Task priorTask) { // Must always wait for prior flushes to complete first, since they are // using _previousOutput and nothing else is allowed to do so if (!priorTask.IsCompletedSuccessfully) { await priorTask; } // Swap buffers var outputToFlush = _currentOutput; _currentOutput = _previousOutput ?? new(PageSize); _previousOutput = outputToFlush; await outputToFlush.WriteToAsync(_underlying, _charArraySegmentBuilder.ToString()); outputToFlush.Clear(); await _underlying.FlushAsync(); } }