Skip to content

Commit ca281db

Browse files
committed
Changes per PR
1 parent f63e13f commit ca281db

27 files changed

+172
-123
lines changed

src/Mvc/Mvc.Core/src/DependencyInjection/MvcCoreServiceCollectionExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ internal static void AddMvcCoreServices(IServiceCollection services)
260260
services.TryAddSingleton<IActionResultExecutor<ContentResult>, ContentResultExecutor>();
261261
services.TryAddSingleton<IActionResultExecutor<JsonResult>, SystemTextJsonResultExecutor>();
262262
services.TryAddSingleton<IClientErrorFactory, ProblemDetailsClientErrorFactory>();
263-
services.TryAddSingleton<AsyncEnumerableReader>();
264263

265264
//
266265
// Route Handlers

src/Mvc/Mvc.Core/src/Infrastructure/AsyncEnumerableReader.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
using System.Threading.Tasks;
1111
using Microsoft.AspNetCore.Mvc.Core;
1212
using Microsoft.Extensions.Internal;
13-
using Microsoft.Extensions.Options;
1413

14+
#if JSONNET
15+
namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
16+
#else
1517
namespace Microsoft.AspNetCore.Mvc.Infrastructure
18+
#endif
1619
{
1720
using ReaderFunc = Func<IAsyncEnumerable<object>, Task<ICollection>>;
1821

@@ -22,10 +25,10 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
2225
/// </summary>
2326
/// <remarks>
2427
/// This type is used to create a strongly typed synchronous <see cref="ICollection{T}"/> instance from
25-
/// an <see cref="IAsyncEnumerable{T}"/>. An accurate <see cref="ICollection{T}"/> is required for XML formatters to
28+
/// an <see cref="IAsyncEnumerable{T}"/>. An accurate <see cref="ICollection{T}"/> is required for XML formatters to
2629
/// correctly serialize.
2730
/// </remarks>
28-
public sealed class AsyncEnumerableReader
31+
internal sealed class AsyncEnumerableReader
2932
{
3033
private readonly MethodInfo Converter = typeof(AsyncEnumerableReader).GetMethod(
3134
nameof(ReadInternal),
@@ -39,9 +42,9 @@ public sealed class AsyncEnumerableReader
3942
/// Initializes a new instance of <see cref="AsyncEnumerableReader"/>.
4043
/// </summary>
4144
/// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
42-
public AsyncEnumerableReader(IOptions<MvcOptions> mvcOptions)
45+
public AsyncEnumerableReader(MvcOptions mvcOptions)
4346
{
44-
_mvcOptions = mvcOptions?.Value ?? throw new ArgumentNullException(nameof(mvcOptions));
47+
_mvcOptions = mvcOptions;
4548
}
4649

4750
/// <summary>

src/Mvc/Mvc.Core/src/Infrastructure/ObjectResultExecutor.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.AspNetCore.Http;
1111
using Microsoft.AspNetCore.Mvc.Formatters;
1212
using Microsoft.Extensions.Logging;
13+
using Microsoft.Extensions.Options;
1314

1415
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1516
{
@@ -31,7 +32,7 @@ public ObjectResultExecutor(
3132
OutputFormatterSelector formatterSelector,
3233
IHttpResponseStreamWriterFactory writerFactory,
3334
ILoggerFactory loggerFactory)
34-
: this(formatterSelector, writerFactory, loggerFactory, asyncEnumerableReader: null)
35+
: this(formatterSelector, writerFactory, loggerFactory, mvcOptions: null)
3536
{
3637
}
3738

@@ -41,12 +42,12 @@ public ObjectResultExecutor(
4142
/// <param name="formatterSelector">The <see cref="OutputFormatterSelector"/>.</param>
4243
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
4344
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
44-
/// <param name="asyncEnumerableReader">The <see cref="AsyncEnumerableReader"/>.</param>
45+
/// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
4546
public ObjectResultExecutor(
4647
OutputFormatterSelector formatterSelector,
4748
IHttpResponseStreamWriterFactory writerFactory,
4849
ILoggerFactory loggerFactory,
49-
AsyncEnumerableReader asyncEnumerableReader)
50+
IOptions<MvcOptions> mvcOptions)
5051
{
5152
if (formatterSelector == null)
5253
{
@@ -66,7 +67,8 @@ public ObjectResultExecutor(
6667
FormatterSelector = formatterSelector;
6768
WriterFactory = writerFactory.CreateWriter;
6869
Logger = loggerFactory.CreateLogger<ObjectResultExecutor>();
69-
_asyncEnumerableReader = asyncEnumerableReader ?? throw new ArgumentNullException(nameof(asyncEnumerableReader));
70+
var options = mvcOptions?.Value ?? throw new ArgumentNullException(nameof(mvcOptions));
71+
_asyncEnumerableReader = new AsyncEnumerableReader(options);
7072
}
7173

7274
/// <summary>
@@ -125,6 +127,8 @@ public virtual Task ExecuteAsync(ActionContext context, ObjectResult result)
125127

126128
private async Task ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, IAsyncEnumerable<object> asyncEnumerable)
127129
{
130+
Log.BufferingAsyncEnumerable(Logger, asyncEnumerable);
131+
128132
var enumerated = await _asyncEnumerableReader.ReadAsync(asyncEnumerable);
129133
await ExecuteAsyncCore(context, result, enumerated.GetType(), enumerated);
130134
}
@@ -178,6 +182,20 @@ private static void InferContentTypes(ActionContext context, ObjectResult result
178182
}
179183
}
180184

181-
185+
private static class Log
186+
{
187+
private static readonly Action<ILogger, string, Exception> _bufferingAsyncEnumerable;
188+
189+
static Log()
190+
{
191+
_bufferingAsyncEnumerable = LoggerMessage.Define<string>(
192+
LogLevel.Debug,
193+
new EventId(1, "BufferingAsyncEnumerable"),
194+
"Buffering IAsyncEnumerable instance of type '{Type}'.");
195+
}
196+
197+
public static void BufferingAsyncEnumerable(ILogger logger, IAsyncEnumerable<object> asyncEnumerable)
198+
=> _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName, null);
199+
}
182200
}
183201
}

src/Mvc/Mvc.Core/src/Infrastructure/SystemTextJsonResultExecutor.cs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ internal sealed class SystemTextJsonResultExecutor : IActionResultExecutor<JsonR
2626

2727
private readonly JsonOptions _options;
2828
private readonly ILogger<SystemTextJsonResultExecutor> _logger;
29-
private readonly AsyncEnumerableReader _reader;
29+
private readonly AsyncEnumerableReader _asyncEnumerableReader;
3030

3131
public SystemTextJsonResultExecutor(
3232
IOptions<JsonOptions> options,
3333
ILogger<SystemTextJsonResultExecutor> logger,
34-
AsyncEnumerableReader reader)
34+
IOptions<MvcOptions> mvcOptions)
3535
{
3636
_options = options.Value;
3737
_logger = logger;
38-
_reader = reader;
38+
_asyncEnumerableReader = new AsyncEnumerableReader(mvcOptions.Value);
3939
}
4040

4141
public async Task ExecuteAsync(ActionContext context, JsonResult result)
@@ -77,8 +77,8 @@ public async Task ExecuteAsync(ActionContext context, JsonResult result)
7777
var value = result.Value;
7878
if (value is IAsyncEnumerable<object> asyncEnumerable)
7979
{
80-
Log.EagerlyReadingAsyncEnumerable(_logger, asyncEnumerable);
81-
value = await _reader.ReadAsync(asyncEnumerable);
80+
Log.BufferingAsyncEnumerable(_logger, asyncEnumerable);
81+
value = await _asyncEnumerableReader.ReadAsync(asyncEnumerable);
8282
}
8383

8484
var type = value?.GetType() ?? typeof(object);
@@ -134,22 +134,19 @@ private static class Log
134134
new EventId(1, "JsonResultExecuting"),
135135
"Executing JsonResult, writing value of type '{Type}'.");
136136

137-
private static readonly Action<ILogger, string, Exception> _eagerlyReadingAsyncEnumerable = LoggerMessage.Define<string>(
137+
private static readonly Action<ILogger, string, Exception> _bufferingAsyncEnumerable = LoggerMessage.Define<string>(
138138
LogLevel.Debug,
139-
new EventId(2, "EagerReadAsyncEnumerable"),
140-
"Eagerly reading IAsyncEnumerable instance of type '{Type}'.");
139+
new EventId(2, "BufferingAsyncEnumerable"),
140+
"Buffering IAsyncEnumerable instance of type '{Type}'.");
141141

142142
public static void JsonResultExecuting(ILogger logger, object value)
143143
{
144144
var type = value == null ? "null" : value.GetType().FullName;
145145
_jsonResultExecuting(logger, type, null);
146146
}
147147

148-
public static void EagerlyReadingAsyncEnumerable(ILogger logger, object value)
149-
{
150-
var type = value == null ? "null" : value.GetType().FullName;
151-
_eagerlyReadingAsyncEnumerable(logger, type, null);
152-
}
148+
public static void BufferingAsyncEnumerable(ILogger logger, IAsyncEnumerable<object> asyncEnumerable)
149+
=> _bufferingAsyncEnumerable(logger, asyncEnumerable.GetType().FullName, null);
153150
}
154151
}
155152
}

src/Mvc/Mvc.Core/src/Properties/Resources.Designer.cs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Mvc/Mvc.Core/src/Resources.resx

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3-
<!--
4-
Microsoft ResX Schema
5-
3+
<!--
4+
Microsoft ResX Schema
5+
66
Version 2.0
7-
8-
The primary goals of this format is to allow a simple XML format
9-
that is mostly human readable. The generation and parsing of the
10-
various data types are done through the TypeConverter classes
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
1111
associated with the data types.
12-
12+
1313
Example:
14-
14+
1515
... ado.net/XML headers & schema ...
1616
<resheader name="resmimetype">text/microsoft-resx</resheader>
1717
<resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
2626
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
2727
<comment>This is a comment</comment>
2828
</data>
29-
30-
There are any number of "resheader" rows that contain simple
29+
30+
There are any number of "resheader" rows that contain simple
3131
name/value pairs.
32-
33-
Each data row contains a name, and value. The row also contains a
34-
type or mimetype. Type corresponds to a .NET class that support
35-
text/value conversion through the TypeConverter architecture.
36-
Classes that don't support this are serialized and stored with the
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
3737
mimetype set.
38-
39-
The mimetype is used for serialized objects, and tells the
40-
ResXResourceReader how to depersist the object. This is currently not
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
4141
extensible. For a given mimetype the value must be set accordingly:
42-
43-
Note - application/x-microsoft.net.object.binary.base64 is the format
44-
that the ResXResourceWriter will generate, however the reader can
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
4545
read any of the formats listed below.
46-
46+
4747
mimetype: application/x-microsoft.net.object.binary.base64
48-
value : The object must be serialized with
48+
value : The object must be serialized with
4949
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
5050
: and then encoded with base64 encoding.
51-
51+
5252
mimetype: application/x-microsoft.net.object.soap.base64
53-
value : The object must be serialized with
53+
value : The object must be serialized with
5454
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
5555
: and then encoded with base64 encoding.
5656
5757
mimetype: application/x-microsoft.net.object.bytearray.base64
58-
value : The object must be serialized into a byte array
58+
value : The object must be serialized into a byte array
5959
: using a System.ComponentModel.TypeConverter
6060
: and then encoded with base64 encoding.
6161
-->
@@ -505,6 +505,6 @@
505505
<value>Property '{0}.{1}' must be an instance of type '{2}'.</value>
506506
</data>
507507
<data name="ObjectResultExecutor_MaxEnumerationExceeded" xml:space="preserve">
508-
<value>'{0}' reached the configured maximum size of the buffer when an enumerating a value of type `{1}'. This limit is in place to prevent infinite streams of `IAsyncEnumerable&lt;&gt;` from continuing indefinitely. If this is not a programming mistake, consider ways to reduce the collection or size, or consider manually converting '{1}' into a list rather than increasing the limit.</value>
508+
<value>'{0}' reached the configured maximum size of the buffer when enumerating a value of type '{1}'. This limit is in place to prevent infinite streams of 'IAsyncEnumerable&lt;&gt;' from continuing indefinitely. If this is not a programming mistake, consider ways to reduce the collection size, or consider manually converting '{1}' into a list rather than increasing the limit.</value>
509509
</data>
510-
</root>
510+
</root>

src/Mvc/Mvc.Core/test/AcceptedAtActionResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ private static IServiceProvider CreateServices(Mock<IOutputFormatter> formatter)
276276
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
277277
new TestHttpResponseStreamWriterFactory(),
278278
NullLoggerFactory.Instance,
279-
new AsyncEnumerableReader(options)));
279+
options));
280280

281281
return services.BuildServiceProvider();
282282
}

src/Mvc/Mvc.Core/test/AcceptedAtRouteResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ private static IServiceProvider CreateServices(Mock<IOutputFormatter> formatter)
184184
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
185185
new TestHttpResponseStreamWriterFactory(),
186186
NullLoggerFactory.Instance,
187-
new AsyncEnumerableReader(Options.Create(new MvcOptions()))));
187+
options));
188188

189189
return services.BuildServiceProvider();
190190
}

src/Mvc/Mvc.Core/test/AcceptedResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private static IServiceProvider CreateServices(Mock<IOutputFormatter> formatter)
140140
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
141141
new TestHttpResponseStreamWriterFactory(),
142142
NullLoggerFactory.Instance,
143-
new AsyncEnumerableReader(options)));
143+
options));
144144

145145
return services.BuildServiceProvider();
146146
}

src/Mvc/Mvc.Core/test/CreatedAtActionResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private static IServiceProvider CreateServices()
9898
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
9999
new TestHttpResponseStreamWriterFactory(),
100100
NullLoggerFactory.Instance,
101-
new AsyncEnumerableReader(options)));
101+
options));
102102

103103
return services.BuildServiceProvider();
104104
}

src/Mvc/Mvc.Core/test/CreatedAtRouteResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private static IServiceProvider CreateServices()
111111
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
112112
new TestHttpResponseStreamWriterFactory(),
113113
NullLoggerFactory.Instance,
114-
new AsyncEnumerableReader(options)));
114+
options));
115115

116116
return services.BuildServiceProvider();
117117
}

src/Mvc/Mvc.Core/test/CreatedResultTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ private static IServiceProvider CreateServices()
9999
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
100100
new TestHttpResponseStreamWriterFactory(),
101101
NullLoggerFactory.Instance,
102-
new AsyncEnumerableReader(options)));
102+
options));
103103

104104
return services.BuildServiceProvider();
105105
}

src/Mvc/Mvc.Core/test/HttpNotFoundObjectResultTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ private static IServiceProvider CreateServices()
7676
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
7777
new TestHttpResponseStreamWriterFactory(),
7878
NullLoggerFactory.Instance,
79-
new AsyncEnumerableReader(options)));
79+
options));
8080

8181
return services.BuildServiceProvider();
8282
}

src/Mvc/Mvc.Core/test/HttpOkObjectResultTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private static IServiceProvider CreateServices()
7777
new DefaultOutputFormatterSelector(options, NullLoggerFactory.Instance),
7878
new TestHttpResponseStreamWriterFactory(),
7979
NullLoggerFactory.Instance,
80-
new AsyncEnumerableReader(options)));
80+
options));
8181

8282
return services.BuildServiceProvider();
8383
}

0 commit comments

Comments
 (0)