{
CheckNotDisposed();
+ _memory = default;
+
if (_stream != null)
{
Debug.Assert(_arrayBufferWriter != null);
if (BytesPending != 0)
{
_arrayBufferWriter.Advance(BytesPending);
- Debug.Assert(BytesPending == _arrayBufferWriter.WrittenCount);
+ BytesPending = 0;
+
#if BUILDING_INBOX_LIBRARY
_stream.Write(_arrayBufferWriter.WrittenSpan);
#else
Debug.Assert(_arrayBufferWriter.WrittenCount == underlyingBuffer.Count);
_stream.Write(underlyingBuffer.Array, underlyingBuffer.Offset, underlyingBuffer.Count);
#endif
+
+ BytesCommitted += _arrayBufferWriter.WrittenCount;
_arrayBufferWriter.Clear();
}
_stream.Flush();
if (BytesPending != 0)
{
_output.Advance(BytesPending);
+ BytesCommitted += BytesPending;
+ BytesPending = 0;
}
}
-
- _memory = default;
- BytesCommitted += BytesPending;
- BytesPending = 0;
}
/// <summary>
{
CheckNotDisposed();
+ _memory = default;
+
if (_stream != null)
{
Debug.Assert(_arrayBufferWriter != null);
if (BytesPending != 0)
{
_arrayBufferWriter.Advance(BytesPending);
- Debug.Assert(BytesPending == _arrayBufferWriter.WrittenCount);
+ BytesPending = 0;
+
#if BUILDING_INBOX_LIBRARY
await _stream.WriteAsync(_arrayBufferWriter.WrittenMemory, cancellationToken).ConfigureAwait(false);
#else
Debug.Assert(_arrayBufferWriter.WrittenCount == underlyingBuffer.Count);
await _stream.WriteAsync(underlyingBuffer.Array, underlyingBuffer.Offset, underlyingBuffer.Count, cancellationToken).ConfigureAwait(false);
#endif
+
+ BytesCommitted += _arrayBufferWriter.WrittenCount;
_arrayBufferWriter.Clear();
}
await _stream.FlushAsync(cancellationToken).ConfigureAwait(false);
if (BytesPending != 0)
{
_output.Advance(BytesPending);
+ BytesCommitted += BytesPending;
+ BytesPending = 0;
}
}
-
- _memory = default;
- BytesCommitted += BytesPending;
- BytesPending = 0;
}
/// <summary>
Debug.Assert(BytesPending != 0);
+ _memory = default;
+
if (_stream != null)
{
Debug.Assert(_arrayBufferWriter != null);
_arrayBufferWriter.Advance(BytesPending);
-
- Debug.Assert(BytesPending == _arrayBufferWriter.WrittenCount);
+ BytesPending = 0;
#if BUILDING_INBOX_LIBRARY
_stream.Write(_arrayBufferWriter.WrittenSpan);
Debug.Assert(_arrayBufferWriter.WrittenCount == underlyingBuffer.Count);
_stream.Write(underlyingBuffer.Array, underlyingBuffer.Offset, underlyingBuffer.Count);
#endif
+ BytesCommitted += _arrayBufferWriter.WrittenCount;
_arrayBufferWriter.Clear();
_memory = _arrayBufferWriter.GetMemory(sizeHint);
Debug.Assert(_output != null);
_output.Advance(BytesPending);
+ BytesCommitted += BytesPending;
+ BytesPending = 0;
_memory = _output.GetMemory(sizeHint);
ThrowHelper.ThrowInvalidOperationException_NeedLargerSpan();
}
}
-
- BytesCommitted += BytesPending;
- BytesPending = 0;
}
private void FirstCallToGetMemory(int requiredSize)
if (_stream != null)
{
Debug.Assert(_arrayBufferWriter != null);
- Debug.Assert(BytesPending == _arrayBufferWriter.WrittenCount);
_memory = _arrayBufferWriter.GetMemory(sizeHint);
Debug.Assert(_memory.Length >= sizeHint);
}
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using Xunit;
using System.Buffers;
-using System.IO;
-using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
-using System.Threading.Tasks;
+using System.IO;
using System.IO.Pipelines;
-using System.Collections.Generic;
using System.Text.Encodings.Web;
using System.Text.Unicode;
-using System.Diagnostics;
+using System.Threading;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Xunit;
namespace System.Text.Json.Tests
{
}
[Theory]
+ [InlineData(false, false)]
+ [InlineData(false, true)]
+ [InlineData(true, false)]
+ [InlineData(true, true)]
+ public async Task FlushToStreamThrows_WriterRemainsInConsistentState(bool useAsync, bool throwFromDispose)
+ {
+ var stream = new ThrowingFromWriteMemoryStream();
+ var jsonUtf8 = new Utf8JsonWriter(stream);
+
+ // Write and flush some of an object.
+ jsonUtf8.WriteStartObject();
+ jsonUtf8.WriteString("someProp1", "someValue1");
+ await jsonUtf8.FlushAsync(useAsync);
+
+ // Write some more, but fail while flushing to write to the underlying stream.
+ stream.ExceptionToThrow = new FormatException("uh oh");
+ jsonUtf8.WriteString("someProp2", "someValue2");
+ Assert.Same(stream.ExceptionToThrow, await Assert.ThrowsAsync<FormatException>(() => jsonUtf8.FlushAsync(useAsync)));
+
+ // Write some more.
+ jsonUtf8.WriteEndObject();
+
+ // Dispose, potentially throwing from the subsequent attempt to flush.
+ if (throwFromDispose)
+ {
+ // Disposing should propagate the new exception
+ stream.ExceptionToThrow = new FormatException("uh oh again");
+ Assert.Same(stream.ExceptionToThrow, await Assert.ThrowsAsync<FormatException>(() => jsonUtf8.DisposeAsync(useAsync)));
+ Assert.Equal("{\"someProp1\":\"someValue1\"", Encoding.UTF8.GetString(stream.ToArray()));
+ }
+ else
+ {
+ // Disposing should not fail.
+ stream.ExceptionToThrow = null;
+ await jsonUtf8.DisposeAsync(useAsync);
+ Assert.Equal("{\"someProp1\":\"someValue1\",\"someProp2\":\"someValue2\"}", Encoding.UTF8.GetString(stream.ToArray()));
+ }
+ }
+
+ private sealed class ThrowingFromWriteMemoryStream : MemoryStream
+ {
+ public Exception ExceptionToThrow { get; set; }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if (ExceptionToThrow != null) throw ExceptionToThrow;
+ base.Write(buffer, offset, count);
+ }
+
+ public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ if (ExceptionToThrow != null) throw ExceptionToThrow;
+ await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
+ }
+ }
+
+ [Theory]
[InlineData(true, true)]
[InlineData(true, false)]
[InlineData(false, true)]
return sb.ToString();
}
+
+ public static async Task FlushAsync(this Utf8JsonWriter writer, bool useAsync)
+ {
+ if (useAsync)
+ {
+ await writer.FlushAsync();
+ }
+ else
+ {
+ writer.Flush();
+ }
+ }
+
+ public static async Task DisposeAsync(this Utf8JsonWriter writer, bool useAsync)
+ {
+ if (useAsync)
+ {
+ await writer.DisposeAsync();
+ }
+ else
+ {
+ writer.Dispose();
+ }
+ }
}
}