Пример #1
0
        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;
                    }
                }
        }
Пример #2
0
        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;
                    }
                }
        }