Skip to content

Commit 0049b66

Browse files
committed
Removed breaking changes
1 parent 0e21d28 commit 0049b66

20 files changed

+149
-87
lines changed

src/Mvc/Mvc.Abstractions/src/Formatters/OutputFormatterWriteContext.cs

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class OutputFormatterWriteContext : OutputFormatterCanWriteContext
2121
/// <param name="writerFactory">The delegate used to create a <see cref="TextWriter"/> for writing the response.</param>
2222
/// <param name="objectType">The <see cref="Type"/> of the object to write to the response.</param>
2323
/// <param name="object">The object to write to the response.</param>
24-
public OutputFormatterWriteContext(HttpContext httpContext, Func<PipeWriter, Encoding, TextWriter> writerFactory, Type objectType, object @object)
24+
public OutputFormatterWriteContext(HttpContext httpContext, Func<Stream, Encoding, TextWriter> writerFactory, Type objectType, object @object)
2525
: base(httpContext)
2626
{
2727
if (writerFactory == null)
@@ -34,6 +34,47 @@ public OutputFormatterWriteContext(HttpContext httpContext, Func<PipeWriter, Enc
3434
Object = @object;
3535
}
3636

37+
/// <summary>
38+
/// Creates a new <see cref="OutputFormatterWriteContext"/>.
39+
/// </summary>
40+
/// <param name="httpContext">The <see cref="Http.HttpContext"/> for the current request.</param>
41+
/// <param name="writerFactory">The delegate used to create a <see cref="TextWriter"/> for writing the response.</param>
42+
/// <param name="objectType">The <see cref="Type"/> of the object to write to the response.</param>
43+
/// <param name="object">The object to write to the response.</param>
44+
public OutputFormatterWriteContext(HttpContext httpContext, Func<PipeWriter, Encoding, TextWriter> writerFactory, Type objectType, object @object)
45+
: base(httpContext)
46+
{
47+
if (writerFactory == null)
48+
{
49+
throw new ArgumentNullException(nameof(writerFactory));
50+
}
51+
52+
PipeWriterFactory = writerFactory;
53+
ObjectType = objectType;
54+
Object = @object;
55+
}
56+
57+
/// <summary>
58+
/// <para>
59+
/// Gets or sets a delegate used to create a <see cref="TextWriter"/> for writing text to the response.
60+
/// </para>
61+
/// <para>
62+
/// Write to <see cref="HttpResponse.Body"/> directly to write binary data to the response.
63+
/// </para>
64+
/// </summary>
65+
/// <remarks>
66+
/// <para>
67+
/// The <see cref="TextWriter"/> created by this delegate will encode text and write to the
68+
/// <see cref="HttpResponse.BodyWriter"/> pipe. Call this delegate to create a <see cref="TextWriter"/>
69+
/// for writing text output to the response pipe.
70+
/// </para>
71+
/// <para>
72+
/// To implement a formatter that writes binary data to the response stream, do not use the
73+
/// <see cref="WriterFactory"/> delegate, and use <see cref="HttpResponse.Body"/> instead.
74+
/// </para>
75+
/// </remarks>
76+
public virtual Func<Stream, Encoding, TextWriter>? WriterFactory { get; protected set; }
77+
3778
/// <summary>
3879
/// <para>
3980
/// Gets or sets a delegate used to create a <see cref="TextWriter"/> for writing text to the response.
@@ -50,9 +91,9 @@ public OutputFormatterWriteContext(HttpContext httpContext, Func<PipeWriter, Enc
5091
/// </para>
5192
/// <para>
5293
/// To implement a formatter that writes binary data to the response stream, do not use the
53-
/// <see cref="WriterFactory"/> delegate, and use <see cref="HttpResponse.BodyWriter"/> instead.
94+
/// <see cref="PipeWriterFactory"/> delegate, and use <see cref="HttpResponse.BodyWriter"/> instead.
5495
/// </para>
5596
/// </remarks>
56-
public virtual Func<PipeWriter, Encoding, TextWriter> WriterFactory { get; protected set; }
97+
public virtual Func<PipeWriter, Encoding, TextWriter>? PipeWriterFactory { get; protected set; }
5798
}
5899
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ internal static void AddMvcCoreServices(IServiceCollection services)
241241
services.TryAddSingleton<ITypeActivatorCache, TypeActivatorCache>();
242242
services.TryAddSingleton<IUrlHelperFactory, UrlHelperFactory>();
243243
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
244-
services.TryAddSingleton<IHttpResponseWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
244+
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
245245
services.TryAddSingleton(ArrayPool<byte>.Shared);
246246
services.TryAddSingleton(ArrayPool<char>.Shared);
247247
services.TryAddSingleton<OutputFormatterSelector, DefaultOutputFormatterSelector>();

src/Mvc/Mvc.Core/src/Infrastructure/ContentResultExecutor.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Threading.Tasks;
66
using Microsoft.AspNetCore.Mvc.Formatters;
7+
using Microsoft.AspNetCore.WebUtilities;
78
using Microsoft.Extensions.Logging;
89

910
namespace Microsoft.AspNetCore.Mvc.Infrastructure
@@ -15,17 +16,22 @@ public class ContentResultExecutor : IActionResultExecutor<ContentResult>
1516
{
1617
private const string DefaultContentType = "text/plain; charset=utf-8";
1718
private readonly ILogger<ContentResultExecutor> _logger;
18-
private readonly IHttpResponseWriterFactory _httpResponsePipeWriterFactory;
19+
private readonly IHttpResponseStreamWriterFactory _httpResponseStreamWriterFactory;
20+
21+
public ContentResultExecutor(ILogger<ContentResultExecutor> logger)
22+
{
23+
_logger = logger;
24+
}
1925

2026
/// <summary>
2127
/// Initializes a new instance of <see cref="ContentResultExecutor"/>.
2228
/// </summary>
2329
/// <param name="logger">The logger to use.</param>
2430
/// <param name="httpResponseStreamWriterFactory">The stream writer factory.</param>
25-
public ContentResultExecutor(ILogger<ContentResultExecutor> logger, IHttpResponseWriterFactory httpResponseStreamWriterFactory)
31+
public ContentResultExecutor(ILogger<ContentResultExecutor> logger, IHttpResponseStreamWriterFactory httpResponseStreamWriterFactory)
2632
{
2733
_logger = logger;
28-
_httpResponsePipeWriterFactory = httpResponseStreamWriterFactory;
34+
_httpResponseStreamWriterFactory = httpResponseStreamWriterFactory;
2935
}
3036

3137
/// <inheritdoc />
@@ -63,7 +69,9 @@ public virtual async Task ExecuteAsync(ActionContext context, ContentResult resu
6369
{
6470
response.ContentLength = resolvedContentTypeEncoding.GetByteCount(result.Content);
6571

66-
await using (var textWriter = _httpResponsePipeWriterFactory.CreateWriter(response.BodyWriter, resolvedContentTypeEncoding))
72+
await using (var textWriter = _httpResponseStreamWriterFactory != null
73+
? _httpResponseStreamWriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding)
74+
: new HttpResponsePipeWriter(response.BodyWriter, resolvedContentTypeEncoding))
6775
{
6876
await textWriter.WriteAsync(result.Content);
6977

src/Mvc/Mvc.Core/src/Infrastructure/IHttpResponseWriterFactory.cs renamed to src/Mvc/Mvc.Core/src/Infrastructure/IHttpResponseStreamWriterFactory.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,21 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.IO;
5-
using System.IO.Pipelines;
65
using System.Text;
76

87
namespace Microsoft.AspNetCore.Mvc.Infrastructure
98
{
109
/// <summary>
11-
/// Creates <see cref="TextWriter"/> instances for writing to <see cref="Http.HttpResponse.Body"/> or <see cref="Http.HttpResponse.BodyWriter"/>.
10+
/// Creates <see cref="TextWriter"/> instances for writing to <see cref="Http.HttpResponse.Body"/>.
1211
/// </summary>
13-
public interface IHttpResponseWriterFactory
12+
public interface IHttpResponseStreamWriterFactory
1413
{
15-
// TODO: remove
1614
/// <summary>
1715
/// Creates a new <see cref="TextWriter"/>.
1816
/// </summary>
1917
/// <param name="stream">The <see cref="Stream"/>, usually <see cref="Http.HttpResponse.Body"/>.</param>
2018
/// <param name="encoding">The <see cref="Encoding"/>, usually <see cref="Encoding.UTF8"/>.</param>
2119
/// <returns>A <see cref="TextWriter"/>.</returns>
2220
TextWriter CreateWriter(Stream stream, Encoding encoding);
23-
24-
/// <summary>
25-
/// Creates a new <see cref="TextWriter"/>.
26-
/// </summary>
27-
/// <param name="writer">The <see cref="PipeWriter"/>, usually <see cref="Http.HttpResponse.BodyWriter"/>.</param>
28-
/// <param name="encoding">The <see cref="Encoding"/>, usually <see cref="Encoding.UTF8"/>.</param>
29-
/// <returns>A <see cref="TextWriter"/>.</returns>
30-
TextWriter CreateWriter(PipeWriter writer, Encoding encoding);
3121
}
3222
}

src/Mvc/Mvc.Core/src/Infrastructure/MemoryPoolHttpResponseStreamWriterFactory.cs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
namespace Microsoft.AspNetCore.Mvc.Infrastructure
1212
{
1313
/// <summary>
14-
/// An <see cref="IHttpResponseWriterFactory"/> that uses pooled buffers.
14+
/// An <see cref="IHttpResponseStreamWriterFactory"/> that uses pooled buffers.
1515
/// </summary>
16-
internal class MemoryPoolHttpResponseStreamWriterFactory : IHttpResponseWriterFactory
16+
internal class MemoryPoolHttpResponseStreamWriterFactory : IHttpResponseStreamWriterFactory
1717
{
1818
/// <summary>
1919
/// The default size of buffers <see cref="HttpResponseStreamWriter"/>s will allocate.
@@ -28,7 +28,6 @@ internal class MemoryPoolHttpResponseStreamWriterFactory : IHttpResponseWriterFa
2828
/// </remarks>
2929
public static readonly int DefaultBufferSize = 16 * 1024;
3030

31-
// TODO: remove
3231
private readonly ArrayPool<byte> _bytePool;
3332
private readonly ArrayPool<char> _charPool;
3433

@@ -60,7 +59,6 @@ public MemoryPoolHttpResponseStreamWriterFactory(
6059
_charPool = charPool;
6160
}
6261

63-
// TODO: remove
6462
/// <inheritdoc />
6563
public TextWriter CreateWriter(Stream stream, Encoding encoding)
6664
{
@@ -76,21 +74,5 @@ public TextWriter CreateWriter(Stream stream, Encoding encoding)
7674

7775
return new HttpResponseStreamWriter(stream, encoding, DefaultBufferSize, _bytePool, _charPool);
7876
}
79-
80-
/// <inheritdoc />
81-
public TextWriter CreateWriter(PipeWriter writer, Encoding encoding)
82-
{
83-
if (writer == null)
84-
{
85-
throw new ArgumentNullException(nameof(writer));
86-
}
87-
88-
if (encoding == null)
89-
{
90-
throw new ArgumentNullException(nameof(encoding));
91-
}
92-
93-
return new HttpResponsePipeWriter(writer, encoding);
94-
}
9577
}
9678
}

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

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Threading.Tasks;
1212
using Microsoft.AspNetCore.Http;
1313
using Microsoft.AspNetCore.Mvc.Formatters;
14+
using Microsoft.AspNetCore.WebUtilities;
1415
using Microsoft.Extensions.Logging;
1516
using Microsoft.Extensions.Options;
1617

@@ -27,12 +28,12 @@ public class ObjectResultExecutor : IActionResultExecutor<ObjectResult>
2728
/// Creates a new <see cref="ObjectResultExecutor"/>.
2829
/// </summary>
2930
/// <param name="formatterSelector">The <see cref="OutputFormatterSelector"/>.</param>
30-
/// <param name="writerFactory">The <see cref="IHttpResponseWriterFactory"/>.</param>
31+
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
3132
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
3233
[Obsolete("This constructor is obsolete and will be removed in a future release.")]
3334
public ObjectResultExecutor(
3435
OutputFormatterSelector formatterSelector,
35-
IHttpResponseWriterFactory writerFactory,
36+
IHttpResponseStreamWriterFactory writerFactory,
3637
ILoggerFactory loggerFactory)
3738
: this(formatterSelector, writerFactory, loggerFactory, mvcOptions: null)
3839
{
@@ -42,12 +43,12 @@ public ObjectResultExecutor(
4243
/// Creates a new <see cref="ObjectResultExecutor"/>.
4344
/// </summary>
4445
/// <param name="formatterSelector">The <see cref="OutputFormatterSelector"/>.</param>
45-
/// <param name="writerFactory">The <see cref="IHttpResponseWriterFactory"/>.</param>
46+
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
4647
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
4748
/// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
4849
public ObjectResultExecutor(
4950
OutputFormatterSelector formatterSelector,
50-
IHttpResponseWriterFactory writerFactory,
51+
IHttpResponseStreamWriterFactory writerFactory,
5152
ILoggerFactory loggerFactory,
5253
IOptions<MvcOptions> mvcOptions)
5354
{
@@ -73,6 +74,34 @@ public ObjectResultExecutor(
7374
_asyncEnumerableReaderFactory = new AsyncEnumerableReader(options);
7475
}
7576

77+
/// <summary>
78+
/// Creates a new <see cref="ObjectResultExecutor"/>.
79+
/// </summary>
80+
/// <param name="formatterSelector">The <see cref="OutputFormatterSelector"/>.</param>
81+
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
82+
/// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
83+
public ObjectResultExecutor(
84+
OutputFormatterSelector formatterSelector,
85+
ILoggerFactory loggerFactory,
86+
IOptions<MvcOptions> mvcOptions)
87+
{
88+
if (formatterSelector == null)
89+
{
90+
throw new ArgumentNullException(nameof(formatterSelector));
91+
}
92+
93+
if (loggerFactory == null)
94+
{
95+
throw new ArgumentNullException(nameof(loggerFactory));
96+
}
97+
98+
FormatterSelector = formatterSelector;
99+
PipeWriterFactory = (writer, encoding) => new HttpResponsePipeWriter(writer, encoding);
100+
Logger = loggerFactory.CreateLogger<ObjectResultExecutor>();
101+
var options = mvcOptions?.Value ?? throw new ArgumentNullException(nameof(mvcOptions));
102+
_asyncEnumerableReaderFactory = new AsyncEnumerableReader(options);
103+
}
104+
76105
/// <summary>
77106
/// Gets the <see cref="ILogger"/>.
78107
/// </summary>
@@ -86,7 +115,12 @@ public ObjectResultExecutor(
86115
/// <summary>
87116
/// Gets the writer factory delegate.
88117
/// </summary>
89-
protected Func<PipeWriter, Encoding, TextWriter> WriterFactory { get; }
118+
protected Func<Stream, Encoding, TextWriter> WriterFactory { get; }
119+
120+
/// <summary>
121+
/// Gets the pipewriter factory delegate.
122+
/// </summary>
123+
protected Func<PipeWriter, Encoding, TextWriter> PipeWriterFactory { get; }
90124

91125
/// <summary>
92126
/// Executes the <see cref="ObjectResult"/>.
@@ -137,11 +171,22 @@ private async Task ExecuteAsyncEnumerable(ActionContext context, ObjectResult re
137171

138172
private Task ExecuteAsyncCore(ActionContext context, ObjectResult result, Type objectType, object value)
139173
{
140-
var formatterContext = new OutputFormatterWriteContext(
141-
context.HttpContext,
142-
WriterFactory,
143-
objectType,
144-
value);
174+
OutputFormatterWriteContext formatterContext;
175+
if (PipeWriterFactory != null) {
176+
formatterContext = new OutputFormatterWriteContext(
177+
context.HttpContext,
178+
PipeWriterFactory,
179+
objectType,
180+
value);
181+
}
182+
else
183+
{
184+
formatterContext = new OutputFormatterWriteContext(
185+
context.HttpContext,
186+
WriterFactory,
187+
objectType,
188+
value);
189+
}
145190

146191
var selectedFormatter = FormatterSelector.SelectFormatter(
147192
formatterContext,

src/Mvc/Mvc.Core/test/ContentResultTest.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,7 @@ private static IServiceCollection CreateServices()
268268

269269
var services = new ServiceCollection();
270270
services.AddSingleton<IActionResultExecutor<ContentResult>>(new ContentResultExecutor(
271-
new Logger<ContentResultExecutor>(NullLoggerFactory.Instance),
272-
new MemoryPoolHttpResponseStreamWriterFactory(ArrayPool<byte>.Shared, charArrayPool.Object)));
271+
new Logger<ContentResultExecutor>(NullLoggerFactory.Instance)));
273272
return services;
274273
}
275274

src/Mvc/Mvc.Formatters.Xml/src/XmlDataContractSerializerOutputFormatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext co
274274

275275
try
276276
{
277-
await using (var textWriter = context.WriterFactory(responseWriter, writerSettings.Encoding))
277+
await using (var textWriter = new HttpResponsePipeWriter(responseWriter, writerSettings.Encoding))
278278
{
279279
using (var xmlWriter = CreateXmlWriter(context, textWriter, writerSettings))
280280
{

src/Mvc/Mvc.Formatters.Xml/src/XmlSerializerOutputFormatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext co
250250

251251
try
252252
{
253-
await using (var textWriter = context.WriterFactory(responseWriter, selectedEncoding))
253+
await using (var textWriter = new HttpResponsePipeWriter(responseWriter, selectedEncoding))
254254
{
255255
using (var xmlWriter = CreateXmlWriter(context, textWriter, writerSettings))
256256
{

src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonOutputFormatter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext co
141141

142142
try
143143
{
144-
await using (var writer = context.WriterFactory(responseWriter, selectedEncoding))
144+
await using (var writer = new HttpResponsePipeWriter(responseWriter, selectedEncoding))
145145
{
146146
using (var jsonWriter = CreateJsonWriter(writer))
147147
{

src/Mvc/Mvc.NewtonsoftJson/src/NewtonsoftJsonResultExecutor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ internal class NewtonsoftJsonResultExecutor : IActionResultExecutor<JsonResult>
2525
Encoding = Encoding.UTF8
2626
}.ToString();
2727

28-
private readonly IHttpResponseWriterFactory _writerFactory;
28+
private readonly IHttpResponseStreamWriterFactory _writerFactory;
2929
private readonly ILogger _logger;
3030
private readonly MvcOptions _mvcOptions;
3131
private readonly MvcNewtonsoftJsonOptions _jsonOptions;
@@ -35,13 +35,13 @@ internal class NewtonsoftJsonResultExecutor : IActionResultExecutor<JsonResult>
3535
/// <summary>
3636
/// Creates a new <see cref="NewtonsoftJsonResultExecutor"/>.
3737
/// </summary>
38-
/// <param name="writerFactory">The <see cref="IHttpResponseWriterFactory"/>.</param>
38+
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
3939
/// <param name="logger">The <see cref="ILogger{NewtonsoftJsonResultExecutor}"/>.</param>
4040
/// <param name="mvcOptions">Accessor to <see cref="MvcOptions"/>.</param>
4141
/// <param name="jsonOptions">Accessor to <see cref="MvcNewtonsoftJsonOptions"/>.</param>
4242
/// <param name="charPool">The <see cref="ArrayPool{Char}"/> for creating <see cref="T:char[]"/> buffers.</param>
4343
public NewtonsoftJsonResultExecutor(
44-
IHttpResponseWriterFactory writerFactory,
44+
IHttpResponseStreamWriterFactory writerFactory,
4545
ILogger<NewtonsoftJsonResultExecutor> logger,
4646
IOptions<MvcOptions> mvcOptions,
4747
IOptions<MvcNewtonsoftJsonOptions> jsonOptions,
@@ -123,7 +123,7 @@ public async Task ExecuteAsync(ActionContext context, JsonResult result)
123123

124124
try
125125
{
126-
await using (var writer = _writerFactory.CreateWriter(responseWriter, resolvedContentTypeEncoding))
126+
await using (var writer = new HttpResponsePipeWriter(responseWriter, resolvedContentTypeEncoding))
127127
{
128128
using var jsonWriter = new JsonTextWriter(writer);
129129
jsonWriter.ArrayPool = _charPool;

0 commit comments

Comments
 (0)