/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="utf8Json"/>. /// </summary> /// <param name="utf8Json">An instance of <see cref="Stream" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (i.e. with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="Stream" /> that is passed in is null. /// </exception> public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) { if (utf8Json == null) { throw new ArgumentNullException(nameof(utf8Json)); } if (!utf8Json.CanWrite) { throw new ArgumentException(SR.StreamNotWritable); } _stream = utf8Json; _arrayBufferWriter = new ArrayBufferWriter <byte>(); _output = default; BytesPending = default; BytesCommitted = default; _memory = default; _inObject = default; _isNotPrimitive = default; _tokenType = default; _currentDepth = default; Options = options; // Only allocate if the user writes a JSON payload beyond the depth that the _allocationFreeContainer can handle. // This way we avoid allocations in the common, default cases, and allocate lazily. _bitStack = default; }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="bufferWriter"/>. /// </summary> /// <param name="bufferWriter">An instance of <see cref="IBufferWriter{Byte}" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (that is, with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="IBufferWriter{Byte}" /> that is passed in is null. /// </exception> public Utf8JsonWriter(IBufferWriter <byte> bufferWriter, JsonWriterOptions options = default) { _output = bufferWriter ?? throw new ArgumentNullException(nameof(bufferWriter)); _options = options; if (_options.MaxDepth == 0) { _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. } }
private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { if (value == null) { writer.WriteNullValue(); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); return; } if (inputType == null) { inputType = value.GetType(); } WriteStack state = default; state.InitializeRoot(inputType, options, supportContinuation: true); bool isFinalBlock; do { // todo: determine best value here // https://github.com/dotnet/runtime/issues/32356 state.FlushThreshold = (int)(bufferWriter.Capacity * .9); isFinalBlock = WriteCore( writer, value, options, ref state, state.Current.JsonClassInfo !.PolicyProperty !.ConverterBase); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
internal void Reset(IBufferWriter <byte> bufferWriter, JsonWriterOptions options) { Debug.Assert(_output is null && _stream is null && _arrayBufferWriter is null); _output = bufferWriter; _options = options; if (_options.MaxDepth == 0) { _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. } }
private static async Task WriteAsyncCore(Stream utf8Json, object?value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { if (value == null) { writer.WriteNullValue(); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); return; } if (inputType == null) { inputType = value.GetType(); } WriteStack state = default; if (options.ReferenceHandling.ShouldWritePreservedReferences()) { state.ReferenceResolver = new DefaultReferenceResolver(writing: true); } state.Current.Initialize(inputType, options); state.Current.CurrentValue = value; bool isFinalBlock; int flushThreshold; do { flushThreshold = (int)(bufferWriter.Capacity * .9); //todo: determine best value here isFinalBlock = Write(writer, originalWriterDepth: 0, flushThreshold, options, ref state); writer.Flush(); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
/// <summary> /// Gets the json representation as string. /// </summary> /// <param name="json">The j.</param> /// <param name="options">The options.</param> /// <returns></returns> public static string AsString( this JsonElement json, JsonWriterOptions options = default) { using var ms = new MemoryStream(); using (var w = new Utf8JsonWriter(ms, options)) { json.WriteTo(w); } var result = Encoding.UTF8.GetString(ms.ToArray()); return(result); }
/// <summary> /// Gets the json representation as string. /// </summary> /// <param name="json">The j.</param> /// <param name="options">The options.</param> /// <returns></returns> public static Stream ToStream( this JsonElement json, JsonWriterOptions options = default) { var ms = new MemoryStream(); using (var w = new Utf8JsonWriter(ms, options)) { json.WriteTo(w); } ms.Seek(0, SeekOrigin.Begin); return(ms); }
private static async Task WriteAsyncCore <TValue>( Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { // We flush the Stream when the buffer is >=90% of capacity. // This threshold is a compromise between buffer utilization and minimizing cases where the buffer // needs to be expanded\doubled because it is not large enough to write the current property or element. // We check for flush after each object property and array element is written to the buffer. // Once the buffer is expanded to contain the largest single element\property, a 90% thresold // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375. const float FlushThreshold = .9f; if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == typeof(object) && value != null) { inputType = value !.GetType(); } WriteStack state = default; state.Initialize(inputType, options, supportContinuation: true); JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase; bool isFinalBlock; do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="utf8Json"/>. /// </summary> /// <param name="utf8Json">An instance of <see cref="Stream" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (that is, with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="Stream" /> that is passed in is null. /// </exception> public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) { if (utf8Json == null) { throw new ArgumentNullException(nameof(utf8Json)); } if (!utf8Json.CanWrite) { throw new ArgumentException(SR.StreamNotWritable); } _stream = utf8Json; _options = options; _arrayBufferWriter = new ArrayBufferWriter <byte>(); }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="bufferWriter"/>. /// </summary> /// <param name="bufferWriter">An instance of <see cref="IBufferWriter{Byte}" /> used as a destination for writing JSON text into.</param> /// <param name="state">If this is the first call to the ctor, pass in a default state. Otherwise, /// capture the state from the previous instance of the <see cref="Utf8JsonWriter"/> and pass that back.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="IBufferWriter{Byte}" /> that is passed in is null. /// </exception> /// <remarks> /// Since this type is a ref struct, it is a stack-only type and all the limitations of ref structs apply to it. /// This is the reason why the ctor accepts a <see cref="JsonWriterState"/>. /// </remarks> public Utf8JsonWriter(IBufferWriter <byte> bufferWriter, JsonWriterState state = default) { _output = bufferWriter ?? throw new ArgumentNullException(nameof(bufferWriter)); _buffered = 0; BytesCommitted = 0; _buffer = _output.GetSpan(); _inObject = state._inObject; _isNotPrimitive = state._isNotPrimitive; _tokenType = state._tokenType; _writerOptions = state._writerOptions; _bitStack = state._bitStack; _currentDepth = state._currentDepth; }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="bufferWriter"/>. /// </summary> /// <param name="bufferWriter">An instance of <see cref="IBufferWriter{Byte}" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (that is, with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="IBufferWriter{Byte}" /> that is passed in is null. /// </exception> public Utf8JsonWriter(IBufferWriter <byte> bufferWriter, JsonWriterOptions options = default) { _output = bufferWriter ?? throw new ArgumentNullException(nameof(bufferWriter)); _stream = default; _arrayBufferWriter = default; BytesPending = default; BytesCommitted = default; _memory = default; _inObject = default; _tokenType = default; _currentDepth = default; _options = options; // Only allocate if the user writes a JSON payload beyond the depth that the _allocationFreeContainer can handle. // This way we avoid allocations in the common, default cases, and allocate lazily. _bitStack = default; }
private static async Task WriteAsyncCore <TValue>(Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == typeof(object) && value != null) { inputType = value !.GetType(); } WriteStack state = default; state.Initialize(inputType, options, supportContinuation: true); JsonConverter converterBase = state.Current.JsonClassInfo !.PropertyInfoForClassInfo.ConverterBase; bool isFinalBlock; do { // todo: determine best value here // https://github.com/dotnet/runtime/issues/32356 state.FlushThreshold = (int)(bufferWriter.Capacity * .9); isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } while (!isFinalBlock); } // todo: verify that we do want to call FlushAsync here (or above). It seems like leaving it to the caller would be best. }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="utf8Json"/>. /// </summary> /// <param name="utf8Json">An instance of <see cref="Stream" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (that is, with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="Stream" /> that is passed in is null. /// </exception> public Utf8JsonWriter(Stream utf8Json, JsonWriterOptions options = default) { if (utf8Json == null) { throw new ArgumentNullException(nameof(utf8Json)); } if (!utf8Json.CanWrite) { throw new ArgumentException(SR.StreamNotWritable); } _stream = utf8Json; _options = options; if (_options.MaxDepth == 0) { _options.MaxDepth = JsonWriterOptions.DefaultMaxDepth; // If max depth is not set, revert to the default depth. } _arrayBufferWriter = new ArrayBufferWriter <byte>(); }
public static string SerializeWithContextUri(this IMetaValue metaValue) { if (metaValue == null) { throw new ArgumentNullException(nameof(metaValue)); } var options = new JsonWriterOptions { Indented = true }; using (var stream = new MemoryStream()) { using (var writer = new Utf8JsonWriter(stream, options)) { metaValue.Serialize(writer); } return(Encoding.UTF8.GetString(stream.ToArray())); } }
private static async Task WriteAsyncCore <TValue>( Stream utf8Json, TValue value, Type inputType, JsonSerializerOptions?options, CancellationToken cancellationToken) { // We flush the Stream when the buffer is >=90% of capacity. // This threshold is a compromise between buffer utilization and minimizing cases where the buffer // needs to be expanded\doubled because it is not large enough to write the current property or element. // We check for flush after each object property and array element is written to the buffer. // Once the buffer is expanded to contain the largest single element\property, a 90% thresold // means the buffer may be expanded a maximum of 4 times: 1-(1\(2^4))==.9375. const float FlushThreshold = .9f; if (options == null) { options = JsonSerializerOptions.s_defaultOptions; } JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { // We treat typeof(object) special and allow polymorphic behavior. if (inputType == JsonTypeInfo.ObjectType && value != null) { inputType = value !.GetType(); } WriteStack state = new WriteStack { CancellationToken = cancellationToken }; JsonConverter converterBase = state.Initialize(inputType, options, supportContinuation: true); bool isFinalBlock; try { do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); try { isFinalBlock = WriteCore(converterBase, writer, value, options, ref state); } finally { if (state.PendingAsyncDisposables?.Count > 0) { await state.DisposePendingAsyncDisposables().ConfigureAwait(false); } } await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); if (state.PendingTask is not null) { try { await state.PendingTask.ConfigureAwait(false); } catch { // Exceptions will be propagated elsewhere // TODO https://github.com/dotnet/runtime/issues/22144 } } } while (!isFinalBlock); } catch { await state.DisposePendingDisposablesOnExceptionAsync().ConfigureAwait(false); throw; } } }
public Utf8JsonWriter(IBufferWriter <byte> writer, JsonWriterOptions options) { }
/// <summary> /// Gets the json representation as Stream. /// </summary> /// <param name="json">The j.</param> /// <param name="options">The options.</param> /// <returns></returns> public static Stream ToStream( this JsonDocument json, JsonWriterOptions options = default) { return(json.RootElement.ToStream(options)); }
/// <summary> /// Gets the json representation as string. /// </summary> /// <param name="json">The j.</param> /// <param name="options">The options.</param> /// <returns></returns> public static string AsString( this JsonDocument json, JsonWriterOptions options = default) { return(json.RootElement.AsString(options)); }
private static async Task WriteStreamAsync <TValue>( Stream utf8Json, TValue value, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) { JsonSerializerOptions options = jsonTypeInfo.Options; JsonWriterOptions writerOptions = options.GetWriterOptions(); using (var bufferWriter = new PooledByteBufferWriter(options.DefaultBufferSize)) using (var writer = new Utf8JsonWriter(bufferWriter, writerOptions)) { WriteStack state = new WriteStack { CancellationToken = cancellationToken }; JsonConverter converter = state.Initialize(jsonTypeInfo, supportContinuation: true); bool isFinalBlock; try { do { state.FlushThreshold = (int)(bufferWriter.Capacity * FlushThreshold); try { isFinalBlock = WriteCore(converter, writer, value, options, ref state); await bufferWriter.WriteToStreamAsync(utf8Json, cancellationToken).ConfigureAwait(false); bufferWriter.Clear(); } finally { // Await any pending resumable converter tasks (currently these can only be IAsyncEnumerator.MoveNextAsync() tasks). // Note that pending tasks are always awaited, even if an exception has been thrown or the cancellation token has fired. if (state.PendingTask is not null) { try { await state.PendingTask.ConfigureAwait(false); } catch { // Exceptions should only be propagated by the resuming converter // TODO https://github.com/dotnet/runtime/issues/22144 } } // Dispose any pending async disposables (currently these can only be completed IAsyncEnumerators). if (state.CompletedAsyncDisposables?.Count > 0) { await state.DisposeCompletedAsyncDisposables().ConfigureAwait(false); } } } while (!isFinalBlock); } catch { // On exception, walk the WriteStack for any orphaned disposables and try to dispose them. await state.DisposePendingDisposablesOnExceptionAsync().ConfigureAwait(false); throw; } } }
/// <summary> /// Constructs a new <see cref="Utf8JsonWriter"/> instance with a specified <paramref name="bufferWriter"/>. /// </summary> /// <param name="bufferWriter">An instance of <see cref="IBufferWriter{Byte}" /> used as a destination for writing JSON text into.</param> /// <param name="options">Defines the customized behavior of the <see cref="Utf8JsonWriter"/> /// By default, the <see cref="Utf8JsonWriter"/> writes JSON minimized (that is, with no extra whitespace) /// and validates that the JSON being written is structurally valid according to JSON RFC.</param> /// <exception cref="ArgumentNullException"> /// Thrown when the instance of <see cref="IBufferWriter{Byte}" /> that is passed in is null. /// </exception> public Utf8JsonWriter(IBufferWriter <byte> bufferWriter, JsonWriterOptions options = default) { _output = bufferWriter ?? throw new ArgumentNullException(nameof(bufferWriter)); _options = options; }