diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/Formatters/OutputFormatterWriteContext.cs b/src/Microsoft.AspNet.Mvc.Abstractions/Formatters/OutputFormatterWriteContext.cs index d78d913e7c..c1b74715cb 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/Formatters/OutputFormatterWriteContext.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/Formatters/OutputFormatterWriteContext.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; +using System.Text; using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Mvc.Formatters @@ -15,16 +17,23 @@ namespace Microsoft.AspNet.Mvc.Formatters /// Creates a new . /// /// The for the current request. + /// The delegate used to create a for writing the response. /// The of the object to write to the response. - /// The object to write to the response. - public OutputFormatterWriteContext(HttpContext httpContext, Type objectType, object @object) + /// The object to write to the response. + public OutputFormatterWriteContext(HttpContext httpContext, Func writerFactory, Type objectType, object @object) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } + if (writerFactory == null) + { + throw new ArgumentNullException(nameof(writerFactory)); + } + HttpContext = httpContext; + WriterFactory = writerFactory; ObjectType = objectType; Object = @object; } @@ -33,5 +42,10 @@ namespace Microsoft.AspNet.Mvc.Formatters /// Gets or sets the context associated with the current operation. /// public virtual HttpContext HttpContext { get; protected set; } + + /// + /// Gets or sets a delegate used to create a for writing the response. + /// + public virtual Func WriterFactory { get; protected set; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Infrastructure/ObjectResultExecutor.cs b/src/Microsoft.AspNet.Mvc.Core/Infrastructure/ObjectResultExecutor.cs index 2b76db181e..160a5a016c 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Infrastructure/ObjectResultExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Infrastructure/ObjectResultExecutor.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; @@ -32,6 +34,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure public ObjectResultExecutor( IOptions options, IActionBindingContextAccessor bindingContextAccessor, + IHttpResponseStreamWriterFactory writerFactory, ILoggerFactory loggerFactory) { if (options == null) @@ -54,6 +57,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure OptionsFormatters = options.Value.OutputFormatters; RespectBrowserAcceptHeader = options.Value.RespectBrowserAcceptHeader; Logger = loggerFactory.CreateLogger(); + WriterFactory = writerFactory.CreateWriter; } /// @@ -76,6 +80,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure /// protected bool RespectBrowserAcceptHeader { get; } + /// + /// Gets the writer factory delegate. + /// + protected Func WriterFactory { get; } + /// /// Executes the . /// @@ -110,7 +119,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure objectType = result.Value?.GetType(); }; - var formatterContext = new OutputFormatterWriteContext(context.HttpContext, objectType, result.Value); + var formatterContext = new OutputFormatterWriteContext( + context.HttpContext, + WriterFactory, + objectType, + result.Value); + var selectedFormatter = SelectFormatter(formatterContext, result.ContentTypes, formatters); if (selectedFormatter == null) { diff --git a/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs index 5706c2c3f7..70ef8c2512 100644 --- a/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs @@ -108,7 +108,7 @@ namespace Microsoft.AspNet.Mvc.Formatters var response = context.HttpContext.Response; var selectedEncoding = context.ContentType?.Encoding ?? Encoding.UTF8; - using (var writer = new HttpResponseStreamWriter(response.Body, selectedEncoding)) + using (var writer = context.WriterFactory(response.Body, selectedEncoding)) { WriteObject(writer, context.Object); } diff --git a/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlDataContractSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlDataContractSerializerOutputFormatter.cs index b4c064eb66..e333ee12a9 100644 --- a/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlDataContractSerializerOutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlDataContractSerializerOutputFormatter.cs @@ -148,17 +148,23 @@ namespace Microsoft.AspNet.Mvc.Formatters } /// - /// Creates a new instance of using the given stream and the . + /// Creates a new instance of using the given and + /// . /// - /// The stream on which the XmlWriter should operate on. + /// + /// The underlying which the should write to. + /// + /// + /// The . + /// /// A new instance of public virtual XmlWriter CreateXmlWriter( - Stream writeStream, + TextWriter writer, XmlWriterSettings xmlWriterSettings) { - if (writeStream == null) + if (writer == null) { - throw new ArgumentNullException(nameof(writeStream)); + throw new ArgumentNullException(nameof(writer)); } if (xmlWriterSettings == null) @@ -166,9 +172,10 @@ namespace Microsoft.AspNet.Mvc.Formatters throw new ArgumentNullException(nameof(xmlWriterSettings)); } - return XmlWriter.Create( - new HttpResponseStreamWriter(writeStream, xmlWriterSettings.Encoding), - xmlWriterSettings); + // We always close the TextWriter, so the XmlWriter shouldn't. + xmlWriterSettings.CloseOutput = false; + + return XmlWriter.Create(writer, xmlWriterSettings); } /// @@ -182,24 +189,26 @@ namespace Microsoft.AspNet.Mvc.Formatters var writerSettings = WriterSettings.Clone(); writerSettings.Encoding = context.ContentType?.Encoding ?? Encoding.UTF8; + // Wrap the object only if there is a wrapping type. var value = context.Object; - - using (var xmlWriter = CreateXmlWriter(context.HttpContext.Response.Body, writerSettings)) + var wrappingType = GetSerializableType(context.ObjectType); + if (wrappingType != null && wrappingType != context.ObjectType) { - var wrappingType = GetSerializableType(context.ObjectType); + var wrapperProvider = WrapperProviderFactories.GetWrapperProvider(new WrapperProviderContext( + declaredType: context.ObjectType, + isSerialization: true)); - // Wrap the object only if there is a wrapping type. - if (wrappingType != null && wrappingType != context.ObjectType) + value = wrapperProvider.Wrap(value); + } + + var dataContractSerializer = GetCachedSerializer(wrappingType); + + using (var textWriter = context.WriterFactory(context.HttpContext.Response.Body, writerSettings.Encoding)) + { + using (var xmlWriter = CreateXmlWriter(textWriter, writerSettings)) { - var wrapperProvider = WrapperProviderFactories.GetWrapperProvider(new WrapperProviderContext( - declaredType: context.ObjectType, - isSerialization: true)); - - value = wrapperProvider.Wrap(value); + dataContractSerializer.WriteObject(xmlWriter, value); } - - var dataContractSerializer = GetCachedSerializer(wrappingType); - dataContractSerializer.WriteObject(xmlWriter, value); } return TaskCache.CompletedTask; diff --git a/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlSerializerOutputFormatter.cs index 01911e37fe..58c281b729 100644 --- a/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlSerializerOutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Formatters.Xml/XmlSerializerOutputFormatter.cs @@ -123,17 +123,23 @@ namespace Microsoft.AspNet.Mvc.Formatters } /// - /// Creates a new instance of using the given stream and the . + /// Creates a new instance of using the given and + /// . /// - /// The stream on which the XmlWriter should operate on. + /// + /// The underlying which the should write to. + /// + /// + /// The . + /// /// A new instance of public virtual XmlWriter CreateXmlWriter( - Stream writeStream, + TextWriter writer, XmlWriterSettings xmlWriterSettings) { - if (writeStream == null) + if (writer == null) { - throw new ArgumentNullException(nameof(writeStream)); + throw new ArgumentNullException(nameof(writer)); } if (xmlWriterSettings == null) @@ -141,9 +147,10 @@ namespace Microsoft.AspNet.Mvc.Formatters throw new ArgumentNullException(nameof(xmlWriterSettings)); } - return XmlWriter.Create( - new HttpResponseStreamWriter(writeStream, xmlWriterSettings.Encoding), - xmlWriterSettings); + // We always close the TextWriter, so the XmlWriter shouldn't. + xmlWriterSettings.CloseOutput = false; + + return XmlWriter.Create(writer, xmlWriterSettings); } /// @@ -159,24 +166,26 @@ namespace Microsoft.AspNet.Mvc.Formatters var writerSettings = WriterSettings.Clone(); writerSettings.Encoding = context.ContentType.Encoding ?? Encoding.UTF8; + // Wrap the object only if there is a wrapping type. var value = context.Object; - - using (var xmlWriter = CreateXmlWriter(context.HttpContext.Response.Body, writerSettings)) + var wrappingType = GetSerializableType(context.ObjectType); + if (wrappingType != null && wrappingType != context.ObjectType) { - var wrappingType = GetSerializableType(context.ObjectType); + var wrapperProvider = WrapperProviderFactories.GetWrapperProvider(new WrapperProviderContext( + declaredType: context.ObjectType, + isSerialization: true)); - // Wrap the object only if there is a wrapping type. - if (wrappingType != null && wrappingType != context.ObjectType) + value = wrapperProvider.Wrap(value); + } + + var xmlSerializer = GetCachedSerializer(wrappingType); + + using (var textWriter = context.WriterFactory(context.HttpContext.Response.Body, writerSettings.Encoding)) + { + using (var xmlWriter = CreateXmlWriter(textWriter, writerSettings)) { - var wrapperProvider = WrapperProviderFactories.GetWrapperProvider(new WrapperProviderContext( - declaredType: context.ObjectType, - isSerialization: true)); - - value = wrapperProvider.Wrap(value); + xmlSerializer.Serialize(xmlWriter, value); } - - var xmlSerializer = GetCachedSerializer(wrappingType); - xmlSerializer.Serialize(xmlWriter, value); } return TaskCache.CompletedTask; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs index 270a3ca166..98328cf60d 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs @@ -98,6 +98,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs index 6c51371fa1..01fe35e3b9 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs @@ -112,6 +112,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs index fdd3dfbb93..1029f2e74e 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs @@ -99,6 +99,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/HttpNotAcceptableOutputFormatterTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/HttpNotAcceptableOutputFormatterTest.cs index f355b79924..97fb18fef3 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/HttpNotAcceptableOutputFormatterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/HttpNotAcceptableOutputFormatterTest.cs @@ -18,7 +18,11 @@ namespace Microsoft.AspNet.Mvc.Formatters // Arrange var formatter = new HttpNotAcceptableOutputFormatter(); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null) { FailedContentNegotiation = failedContentNegotiation, }; @@ -36,7 +40,11 @@ namespace Microsoft.AspNet.Mvc.Formatters // Arrange var formatter = new HttpNotAcceptableOutputFormatter(); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null) { FailedContentNegotiation = true, }; @@ -54,7 +62,11 @@ namespace Microsoft.AspNet.Mvc.Formatters // Arrange var formatter = new HttpNotAcceptableOutputFormatter(); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); // Act await formatter.WriteAsync(context); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs index a43377e867..50526d4012 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/NoContentFormatterTests.cs @@ -43,7 +43,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var type = declaredTypeAsString ? typeof(string) : typeof(object); var contentType = useNonNullContentType ? MediaTypeHeaderValue.Parse("text/plain") : null; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), type, value) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + type, + value) { ContentType = contentType, }; @@ -65,6 +69,7 @@ namespace Microsoft.AspNet.Mvc.Formatters // Arrange var context = new OutputFormatterWriteContext( new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, declaredType, "Something non null.") { @@ -92,6 +97,7 @@ namespace Microsoft.AspNet.Mvc.Formatters // Arrange var context = new OutputFormatterWriteContext( new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, typeof(string), value) { @@ -114,7 +120,11 @@ namespace Microsoft.AspNet.Mvc.Formatters public async Task WriteAsync_WritesTheStatusCode204() { // Arrange - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), typeof(string), @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(string), + @object: null); var formatter = new HttpNoContentOutputFormatter(); @@ -132,7 +142,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var httpContext = new DefaultHttpContext(); httpContext.Response.StatusCode = StatusCodes.Status201Created; - var context = new OutputFormatterWriteContext(httpContext, typeof(string), @object: null); + var context = new OutputFormatterWriteContext( + httpContext, + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(string), + @object: null); var formatter = new HttpNoContentOutputFormatter(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/OutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/OutputFormatterTests.cs index f025646edb..5954a183a1 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/OutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/OutputFormatterTests.cs @@ -53,7 +53,11 @@ namespace Microsoft.AspNet.Mvc.Formatters formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding)); } - var context = new OutputFormatterWriteContext(httpContext.Object, typeof(string), "someValue") + var context = new OutputFormatterWriteContext( + httpContext.Object, + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(string), + "someValue") { ContentType = MediaTypeHeaderValue.Parse(httpRequest.Headers[HeaderNames.Accept]), }; @@ -77,7 +81,11 @@ namespace Microsoft.AspNet.Mvc.Formatters formatter.SupportedMediaTypes.Clear(); formatter.SupportedMediaTypes.Add(testContentType); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null) { ContentType = testContentType, }; @@ -102,7 +110,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var mediaType = new MediaTypeHeaderValue("image/png"); formatter.SupportedMediaTypes.Add(mediaType); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); // Act await formatter.WriteAsync(context); @@ -117,7 +129,12 @@ namespace Microsoft.AspNet.Mvc.Formatters public void CanWriteResult_ForNullContentType_UsesFirstEntryInSupportedContentTypes() { // Arrange - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + var formatter = new TestOutputFormatter(); // Act @@ -151,7 +168,11 @@ namespace Microsoft.AspNet.Mvc.Formatters formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); formatter.SupportedTypes.Add(typeof(int)); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(),typeof(string), "Hello, world!") + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(string), + "Hello, world!") { ContentType = formatter.SupportedMediaTypes[0], }; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StreamOutputFormatterTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StreamOutputFormatterTest.cs index 7f529e653e..2a4598b4df 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StreamOutputFormatterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StreamOutputFormatterTest.cs @@ -23,7 +23,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var formatter = new StreamOutputFormatter(); var contentTypeHeader = contentType == null ? null : new MediaTypeHeaderValue(contentType); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), type, new MemoryStream()) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + type, + new MemoryStream()) { ContentType = contentTypeHeader, }; @@ -44,7 +48,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var formatter = new StreamOutputFormatter(); var contentTypeHeader = contentType == null ? null : new MediaTypeHeaderValue(contentType); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), type, new SimplePOCO()) + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + type, + new SimplePOCO()) { ContentType = contentTypeHeader, }; @@ -66,7 +74,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var formatter = new StreamOutputFormatter(); var @object = type != null ? Activator.CreateInstance(type) : null; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), type, @object); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + type, + @object); // Act var result = formatter.CanWriteResult(context); @@ -90,7 +102,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var bufferingFeature = new TestBufferingFeature(); httpContext.Features.Set(bufferingFeature); - var context = new OutputFormatterWriteContext(httpContext, typeof(Stream), new MemoryStream(expected)); + var context = new OutputFormatterWriteContext( + httpContext, + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(Stream), + new MemoryStream(expected)); // Act await formatter.WriteAsync(context); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StringOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StringOutputFormatterTests.cs index bd7510c55c..e8222d6c5d 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StringOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/StringOutputFormatterTests.cs @@ -42,7 +42,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var formatter = new StringOutputFormatter(); var type = useDeclaredTypeAsString ? typeof(string) : typeof(object); - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), type, value); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + type, + value); context.ContentType = MediaTypeHeaderValue.Parse("application/json"); // Act @@ -66,7 +70,11 @@ namespace Microsoft.AspNet.Mvc.Formatters httpContext.Setup(o => o.Response).Returns(response.Object); var formatter = new StringOutputFormatter(); - var context = new OutputFormatterWriteContext(httpContext.Object, typeof(string), @object: null); + var context = new OutputFormatterWriteContext( + httpContext.Object, + new TestHttpResponseStreamWriterFactory().CreateWriter, + typeof(string), + @object: null); // Act await formatter.WriteResponseBodyAsync(context); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs index 6ffa9a84bb..481398d5b1 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs @@ -75,6 +75,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs index ef378c1990..135ca9044b 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs @@ -79,6 +79,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Infrastructure/ObjectResultExecutorTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Infrastructure/ObjectResultExecutorTest.cs index 142fa5b9be..de8b84005d 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Infrastructure/ObjectResultExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Infrastructure/ObjectResultExecutorTest.cs @@ -32,7 +32,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestJsonOutputFormatter(), // This will be chosen based on the accept header }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + context.HttpContext.Request.Headers[HeaderNames.Accept] = "application/json"; // Act @@ -58,7 +63,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestJsonOutputFormatter(), // This will be chosen based on the content type }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + context.HttpContext.Request.Headers[HeaderNames.Accept] = "application/xml"; // This will not be used // Act @@ -83,7 +93,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestXmlOutputFormatter(), }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + context.HttpContext.Request.Headers[HeaderNames.Accept] = "application/xml"; // This will not be used // Act @@ -150,7 +165,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestJsonOutputFormatter(), }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + context.HttpContext.Request.Headers[HeaderNames.Accept] = acceptHeader; // Act @@ -177,7 +197,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestXmlOutputFormatter(), }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); // Act var formatter = executor.SelectFormatter( @@ -203,7 +227,12 @@ namespace Microsoft.AspNet.Mvc.Infrastructure new TestJsonOutputFormatter(), }; - var context = new OutputFormatterWriteContext(new DefaultHttpContext(), objectType: null, @object: null); + var context = new OutputFormatterWriteContext( + new DefaultHttpContext(), + new TestHttpResponseStreamWriterFactory().CreateWriter, + objectType: null, + @object: null); + context.HttpContext.Request.Headers[HeaderNames.Accept] = "text/custom, application/custom"; // Act @@ -434,6 +463,7 @@ namespace Microsoft.AspNet.Mvc.Infrastructure return new TestObjectResultExecutor( options ?? new TestOptionsManager(), bindingContextAccessor, + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance); } @@ -486,9 +516,10 @@ namespace Microsoft.AspNet.Mvc.Infrastructure { public TestObjectResultExecutor( IOptions options, - IActionBindingContextAccessor bindingContextAccessor, + IActionBindingContextAccessor bindingContextAccessor, + IHttpResponseStreamWriterFactory writerFactory, ILoggerFactory loggerFactory) - : base(options, bindingContextAccessor, loggerFactory) + : base(options, bindingContextAccessor, writerFactory, loggerFactory) { } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs index bd49125f55..d9fa58afec 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs @@ -68,6 +68,7 @@ namespace Microsoft.AspNet.Mvc services.AddInstance(new ObjectResultExecutor( new TestOptionsManager(), new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); services.AddInstance(NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs index 3155b0461e..b748f0f9bf 100644 --- a/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs @@ -175,6 +175,7 @@ namespace Microsoft.AspNet.Mvc.Formatters var outputFormatterContext = new OutputFormatterWriteContext( actionContext.HttpContext, + new TestHttpResponseStreamWriterFactory().CreateWriter, typeof(string), content) { @@ -218,7 +219,11 @@ namespace Microsoft.AspNet.Mvc.Formatters var mediaTypeHeaderValue = MediaTypeHeaderValue.Parse(contentType); var actionContext = GetActionContext(mediaTypeHeaderValue, responseStream); - return new OutputFormatterWriteContext(actionContext.HttpContext, outputType, outputValue) + return new OutputFormatterWriteContext( + actionContext.HttpContext, + new TestHttpResponseStreamWriterFactory().CreateWriter, + outputType, + outputValue) { ContentType = mediaTypeHeaderValue, }; diff --git a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlDataContractSerializerOutputFormatterTest.cs b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlDataContractSerializerOutputFormatterTest.cs index 3f7b03c8db..09eb667e90 100644 --- a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlDataContractSerializerOutputFormatterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlDataContractSerializerOutputFormatterTest.cs @@ -599,7 +599,11 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml Type outputType, string contentType = "application/xml; charset=utf-8") { - return new OutputFormatterWriteContext(GetHttpContext(contentType), outputType, outputValue); + return new OutputFormatterWriteContext( + GetHttpContext(contentType), + new TestHttpResponseStreamWriterFactory().CreateWriter, + outputType, + outputValue); } private static HttpContext GetHttpContext(string contentType) diff --git a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlSerializerOutputFormatterTest.cs b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlSerializerOutputFormatterTest.cs index 405afe8225..8aec54e7e3 100644 --- a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlSerializerOutputFormatterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/XmlSerializerOutputFormatterTest.cs @@ -360,7 +360,11 @@ namespace Microsoft.AspNet.Mvc.Formatters.Xml Type outputType, string contentType = "application/xml; charset=utf-8") { - return new OutputFormatterWriteContext(GetHttpContext(contentType), outputType, outputValue); + return new OutputFormatterWriteContext( + GetHttpContext(contentType), + new TestHttpResponseStreamWriterFactory().CreateWriter, + outputType, + outputValue); } private static HttpContext GetHttpContext(string contentType) diff --git a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/project.json b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/project.json index 38dbc63984..d8562f761f 100644 --- a/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/project.json +++ b/test/Microsoft.AspNet.Mvc.Formatters.Xml.Test/project.json @@ -4,9 +4,11 @@ }, "dependencies": { "Microsoft.AspNet.Http": "1.0.0-*", - "Microsoft.AspNet.Mvc" : "6.0.0-*", + "Microsoft.AspNet.Mvc": "6.0.0-*", "Microsoft.AspNet.Mvc.Formatters.Xml" : "6.0.0-*", + "Microsoft.AspNet.Mvc.TestCommon": { "type": "build", "version": "6.0.0-*" }, "Microsoft.AspNet.Testing": "1.0.0-*", + "Microsoft.Extensions.WebEncoders.Testing": "1.0.0-*", "Moq": "4.2.1312.1622", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/BadRequestErrorMessageResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/BadRequestErrorMessageResultTest.cs index e0a137f926..69309a1358 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/BadRequestErrorMessageResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/BadRequestErrorMessageResultTest.cs @@ -77,6 +77,7 @@ namespace System.Web.Http services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ExceptionResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ExceptionResultTest.cs index af8d749d41..b9ddcfeb3a 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ExceptionResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ExceptionResultTest.cs @@ -77,6 +77,7 @@ namespace System.Web.Http services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/HttpResponseMessageOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/HttpResponseMessageOutputFormatterTests.cs index f60149c2d1..ede1a793ad 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/HttpResponseMessageOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/HttpResponseMessageOutputFormatterTests.cs @@ -151,7 +151,11 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShimTest Type outputType, HttpContext httpContext) { - return new OutputFormatterWriteContext(httpContext, outputType, outputValue); + return new OutputFormatterWriteContext( + httpContext, + new TestHttpResponseStreamWriterFactory().CreateWriter, + outputType, + outputValue); } } } diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/InvalidModelStateResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/InvalidModelStateResultTest.cs index f1c3614cd8..4b3f45f30e 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/InvalidModelStateResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/InvalidModelStateResultTest.cs @@ -90,6 +90,7 @@ namespace System.Web.Http services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/NegotiatedContentResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/NegotiatedContentResultTest.cs index dd7f6eafe8..55eb359323 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/NegotiatedContentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/NegotiatedContentResultTest.cs @@ -77,6 +77,7 @@ namespace System.Web.Http services.AddInstance(new ObjectResultExecutor( options, new ActionBindingContextAccessor(), + new TestHttpResponseStreamWriterFactory(), NullLoggerFactory.Instance)); return services.BuildServiceProvider(); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs new file mode 100644 index 0000000000..4bb4cd05ab --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/TestHttpResponseStreamWriterFactory.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using System.Text; +using Microsoft.AspNet.Mvc.Infrastructure; + +namespace Microsoft.AspNet.Mvc +{ + public class TestHttpResponseStreamWriterFactory : IHttpResponseStreamWriterFactory + { + public TextWriter CreateWriter(Stream stream, Encoding encoding) + { + return new HttpResponseStreamWriter(stream, encoding); + } + } +}