/// <summary>
        /// Creates a new <see cref="NewtonsoftJsonResultExecutor"/>.
        /// </summary>
        /// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
        /// <param name="logger">The <see cref="ILogger{NewtonsoftJsonResultExecutor}"/>.</param>
        /// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
        /// <param name="jsonOptions">Accessor to <see cref="MvcNewtonsoftJsonOptions"/>.</param>
        /// <param name="charPool">The <see cref="ArrayPool{Char}"/> for creating <see cref="T:char[]"/> buffers.</param>
        public NewtonsoftJsonResultExecutor(
            IHttpResponseStreamWriterFactory writerFactory,
            ILogger <NewtonsoftJsonResultExecutor> logger,
            IOptions <MvcOptions> mvcOptions,
            IOptions <MvcNewtonsoftJsonOptions> jsonOptions,
            ArrayPool <char> charPool)
        {
            if (writerFactory == null)
            {
                throw new ArgumentNullException(nameof(writerFactory));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            if (jsonOptions == null)
            {
                throw new ArgumentNullException(nameof(jsonOptions));
            }

            if (charPool == null)
            {
                throw new ArgumentNullException(nameof(charPool));
            }

            _writerFactory = writerFactory;
            _logger        = logger;
            _mvcOptions    = mvcOptions?.Value ?? throw new ArgumentNullException(nameof(mvcOptions));
            _jsonOptions   = jsonOptions.Value;
            _charPool      = new JsonArrayPool <char>(charPool);
            _asyncEnumerableReaderFactory = new AsyncEnumerableReader(_mvcOptions);
        }
    /// <summary>
    /// Initializes a new <see cref="NewtonsoftJsonOutputFormatter"/> instance.
    /// </summary>
    /// <param name="serializerSettings">
    /// The <see cref="JsonSerializerSettings"/>. Should be either the application-wide settings
    /// (<see cref="MvcNewtonsoftJsonOptions.SerializerSettings"/>) or an instance
    /// <see cref="JsonSerializerSettingsProvider.CreateSerializerSettings"/> initially returned.
    /// </param>
    /// <param name="charPool">The <see cref="ArrayPool{Char}"/>.</param>
    /// <param name="mvcOptions">The <see cref="MvcOptions"/>.</param>
    /// <param name="jsonOptions">The <see cref="MvcNewtonsoftJsonOptions"/>.</param>
    public NewtonsoftJsonOutputFormatter(
        JsonSerializerSettings serializerSettings,
        ArrayPool <char> charPool,
        MvcOptions mvcOptions,
        MvcNewtonsoftJsonOptions?jsonOptions)
    {
        if (serializerSettings == null)
        {
            throw new ArgumentNullException(nameof(serializerSettings));
        }

        if (charPool == null)
        {
            throw new ArgumentNullException(nameof(charPool));
        }

        SerializerSettings = serializerSettings;
        _charPool          = new JsonArrayPool <char>(charPool);
        _mvcOptions        = mvcOptions ?? throw new ArgumentNullException(nameof(mvcOptions));
        _jsonOptions       = jsonOptions;

        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
        SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson);
        SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson);
        SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);

        _asyncEnumerableReaderFactory = new AsyncEnumerableReader(_mvcOptions);
    }
    public async Task Reader_ThrowsIfIAsyncEnumerableThrows()
    {
        // Arrange
        var enumerable    = ThrowingAsyncEnumerable();
        var options       = new MvcOptions();
        var readerFactory = new AsyncEnumerableReader(options);

        // Act & Assert
        Assert.True(readerFactory.TryGetReader(enumerable.GetType(), out var reader));
        await Assert.ThrowsAsync <TimeZoneNotFoundException>(() => reader(enumerable, default));
    }
    public void TryGetReader_ReturnsFalse_IfTypeIsNotIAsyncEnumerable(Type type)
    {
        // Arrange
        var options         = new MvcOptions();
        var readerFactory   = new AsyncEnumerableReader(options);
        var asyncEnumerable = TestEnumerable();

        // Act
        var result = readerFactory.TryGetReader(type, out var reader);

        // Assert
        Assert.False(result);
    }
    public void TryGetReader_ReturnsCachedDelegate_WhenTypeImplementsMultipleIAsyncEnumerableContracts()
    {
        // Arrange
        var options          = new MvcOptions();
        var readerFactory    = new AsyncEnumerableReader(options);
        var asyncEnumerable1 = new MultiAsyncEnumerable();
        var asyncEnumerable2 = new MultiAsyncEnumerable();

        // Act
        Assert.True(readerFactory.TryGetReader(asyncEnumerable1.GetType(), out var reader1));
        Assert.True(readerFactory.TryGetReader(asyncEnumerable2.GetType(), out var reader2));

        // Assert
        Assert.Same(reader1, reader2);
    }
    public void TryGetReader_ReturnsCachedDelegate()
    {
        // Arrange
        var options          = new MvcOptions();
        var readerFactory    = new AsyncEnumerableReader(options);
        var asyncEnumerable1 = TestEnumerable();
        var asyncEnumerable2 = TestEnumerable();

        // Act
        Assert.True(readerFactory.TryGetReader(asyncEnumerable1.GetType(), out var reader1));
        Assert.True(readerFactory.TryGetReader(asyncEnumerable2.GetType(), out var reader2));

        // Assert
        Assert.Same(reader1, reader2);
    }
    public void TryGetReader_ReturnsDifferentInstancesForDifferentEnumerables()
    {
        // Arrange
        var options       = new MvcOptions();
        var readerFactory = new AsyncEnumerableReader(options);
        var enumerable1   = TestEnumerable();
        var enumerable2   = TestEnumerable2();

        // Act
        Assert.True(readerFactory.TryGetReader(enumerable1.GetType(), out var reader1));
        Assert.True(readerFactory.TryGetReader(enumerable2.GetType(), out var reader2));

        // Assert
        Assert.NotSame(reader1, reader2);
    }
    public async Task CachedDelegate_CanReadEnumerableInstanceMultipleTimes_ThatProduceDifferentResults()
    {
        // Arrange
        var options          = new MvcOptions();
        var readerFactory    = new AsyncEnumerableReader(options);
        var asyncEnumerable1 = TestEnumerable();
        var asyncEnumerable2 = TestEnumerable(4);

        // Act
        Assert.True(readerFactory.TryGetReader(asyncEnumerable1.GetType(), out var reader));

        // Assert
        Assert.Equal(new[] { "0", "1", "2" }, await reader(asyncEnumerable1, default));
        Assert.Equal(new[] { "0", "1", "2", "3" }, await reader(asyncEnumerable2, default));
    }
    public async Task Reader_PassesCancellationTokenToIAsyncEnumerable()
    {
        // Arrange
        var enumerable          = AsyncEnumerable();
        var options             = new MvcOptions();
        CancellationToken token = default;
        var readerFactory       = new AsyncEnumerableReader(options);
        var cts = new CancellationTokenSource();

        // Act & Assert
        Assert.True(readerFactory.TryGetReader(enumerable.GetType(), out var reader));
        await reader(enumerable, cts.Token);

        cts.Cancel();
        Assert.Equal(cts.Token, token);

        async IAsyncEnumerable <string> AsyncEnumerable([EnumeratorCancellation] CancellationToken cancellationToken = default)
Пример #10
0
    public async Task TryGetReader_ReturnsReaderForIAsyncEnumerableOfValueType()
    {
        // Arrange
        var options         = new MvcOptions();
        var readerFactory   = new AsyncEnumerableReader(options);
        var asyncEnumerable = PrimitiveEnumerable();

        // Act
        var result = readerFactory.TryGetReader(asyncEnumerable.GetType(), out var reader);

        // Assert
        Assert.True(result);
        var readCollection = await reader(asyncEnumerable, default);

        var collection = Assert.IsAssignableFrom <ICollection <int> >(readCollection);

        Assert.Equal(new[] { 0, 1, 2, }, collection);
    }
Пример #11
0
    public async Task TryGetReader_ReturnsReaderForIAsyncEnumerable()
    {
        // Arrange
        var options         = new MvcOptions();
        var readerFactory   = new AsyncEnumerableReader(options);
        var asyncEnumerable = TestEnumerable();

        // Act
        var result = readerFactory.TryGetReader(asyncEnumerable.GetType(), out var reader);

        // Assert
        Assert.True(result);
        var readCollection = await reader(asyncEnumerable, default);

        var collection = Assert.IsAssignableFrom <ICollection <string> >(readCollection);

        Assert.Equal(new[] { "0", "1", "2", }, collection);
    }
Пример #12
0
    public async Task Reader_ThrowsIfBufferLimitIsReached()
    {
        // Arrange
        var enumerable = TestEnumerable(11);
        var expected   = $"'AsyncEnumerableReader' reached the configured maximum size of the buffer when enumerating a value of type '{enumerable.GetType()}'. " +
                         "This limit is in place to prevent infinite streams of 'IAsyncEnumerable<>' from continuing indefinitely. If this is not a programming mistake, " +
                         $"consider ways to reduce the collection size, or consider manually converting '{enumerable.GetType()}' into a list rather than increasing the limit.";
        var options = new MvcOptions {
            MaxIAsyncEnumerableBufferLimit = 10
        };
        var readerFactory = new AsyncEnumerableReader(options);

        // Act
        Assert.True(readerFactory.TryGetReader(enumerable.GetType(), out var reader));
        var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => reader(enumerable, default));

        // Assert
        Assert.Equal(expected, ex.Message);
    }
Пример #13
0
    public async Task Reader_ReadsIAsyncEnumerable_ImplementingMultipleAsyncEnumerableInterfaces()
    {
        // This test ensures the reader does not fail if you have a type that implements IAsyncEnumerable for multiple Ts
        // Arrange
        var options         = new MvcOptions();
        var readerFactory   = new AsyncEnumerableReader(options);
        var asyncEnumerable = new MultiAsyncEnumerable();

        // Act
        var result = readerFactory.TryGetReader(asyncEnumerable.GetType(), out var reader);

        // Assert
        Assert.True(result);
        var readCollection = await reader(asyncEnumerable, default);

        var collection = Assert.IsAssignableFrom <ICollection <object> >(readCollection);

        Assert.Equal(new[] { "0", "1", "2", }, collection);
    }