From 0e9091f0eb7ba7db0334b04d14e47163b14d726d Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Mon, 19 Jan 2015 10:14:10 -0800 Subject: [PATCH] [Fixes #1841] Change XML DCS and XmlSerializer output formatters to not derive from the base XmlOutputFormatter --- .../Formatters/FormattingUtilities.cs | 14 ++++ ...mlDataContractSerializerOutputFormatter.cs | 52 ++++++++++++- .../Formatters/XmlOutputFormatter.cs | 77 ------------------- .../XmlSerializerOutputFormatter.cs | 52 ++++++++++++- .../MvcOptionsExtensions.cs | 3 +- .../ActionResults/ObjectResultTests.cs | 6 +- ...aContractSerializerOutputFormatterTests.cs | 54 ++++++++++--- .../XmlSerializerOutputFormatterTests.cs | 54 ++++++++++--- 8 files changed, 202 insertions(+), 110 deletions(-) delete mode 100644 src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/FormattingUtilities.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/FormattingUtilities.cs index db52d37d35..9bd88e22c7 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/FormattingUtilities.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/FormattingUtilities.cs @@ -34,5 +34,19 @@ namespace Microsoft.AspNet.Mvc MaxStringContentLength = int.MaxValue }; } + + /// + /// Gets the default XmlWriterSettings. + /// + /// Default + public static XmlWriterSettings GetDefaultXmlWriterSettings() + { + return new XmlWriterSettings + { + OmitXmlDeclaration = true, + CloseOutput = false, + CheckCharacters = false + }; + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs index b7fcbbdd74..92a25916f9 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs @@ -2,9 +2,11 @@ // 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.Runtime.Serialization; using System.Threading.Tasks; using System.Xml; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc { @@ -12,14 +14,14 @@ namespace Microsoft.AspNet.Mvc /// This class handles serialization of objects /// to XML using /// - public class XmlDataContractSerializerOutputFormatter : XmlOutputFormatter + public class XmlDataContractSerializerOutputFormatter : OutputFormatter { /// /// Initializes a new instance of /// with default XmlWriterSettings /// - public XmlDataContractSerializerOutputFormatter() - : this(GetDefaultXmlWriterSettings()) + public XmlDataContractSerializerOutputFormatter() : + this(FormattingUtilities.GetDefaultXmlWriterSettings()) { } @@ -28,8 +30,39 @@ namespace Microsoft.AspNet.Mvc /// /// The settings to be used by the . public XmlDataContractSerializerOutputFormatter([NotNull] XmlWriterSettings writerSettings) - : base(writerSettings) { + SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM); + SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian); + + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml")); + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml")); + + WriterSettings = writerSettings; + } + + /// + /// Gets the settings to be used by the XmlWriter. + /// + public XmlWriterSettings WriterSettings { get; } + + /// + /// Gets the type of the object to be serialized. + /// + /// The declared type. + /// The runtime type. + /// The type of the object to be serialized. + protected virtual Type GetSerializableType(Type declaredType, Type runtimeType) + { + if (declaredType == null || + declaredType == typeof(object)) + { + if (runtimeType != null) + { + return runtimeType; + } + } + + return declaredType; } /// @@ -62,6 +95,17 @@ namespace Microsoft.AspNet.Mvc } } + /// + /// Creates a new instance of using the given stream and the . + /// + /// The stream on which the XmlWriter should operate on. + /// A new instance of + public virtual XmlWriter CreateXmlWriter([NotNull] Stream writeStream, + [NotNull] XmlWriterSettings xmlWriterSettings) + { + return XmlWriter.Create(writeStream, xmlWriterSettings); + } + /// public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context) { diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs deleted file mode 100644 index d494d71726..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. -// 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.Xml; -using Microsoft.Net.Http.Headers; - -namespace Microsoft.AspNet.Mvc -{ - /// - /// Abstract base class from which all XML Output Formatters derive from. - /// - public abstract class XmlOutputFormatter : OutputFormatter - { - public XmlOutputFormatter([NotNull] XmlWriterSettings xmlWriterSettings) - { - SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM); - SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian); - - SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml")); - SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml")); - - WriterSettings = xmlWriterSettings; - } - - /// - /// Gets or sets the settings to be used by the XmlWriter. - /// - public XmlWriterSettings WriterSettings { get; private set; } - - /// - /// Gets the type of the object to be serialized. - /// - /// The declared type. - /// The runtime type. - /// The type of the object to be serialized. - protected virtual Type GetSerializableType(Type declaredType, Type runtimeType) - { - if (declaredType == null || - declaredType == typeof(object)) - { - if (runtimeType != null) - { - return runtimeType; - } - } - - return declaredType; - } - - /// - /// Gets the default XmlWriterSettings. - /// - /// Default - public static XmlWriterSettings GetDefaultXmlWriterSettings() - { - return new XmlWriterSettings - { - OmitXmlDeclaration = true, - CloseOutput = false, - CheckCharacters = false - }; - } - - /// - /// Creates a new instance of using the given stream and the WriterSettings. - /// - /// The stream on which the XmlWriter should operate on. - /// A new instance of - public virtual XmlWriter CreateXmlWriter([NotNull] Stream writeStream, - [NotNull] XmlWriterSettings xmlWriterSettings) - { - return XmlWriter.Create(writeStream, xmlWriterSettings); - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs index fc48093881..a2572a26a7 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs @@ -2,9 +2,11 @@ // 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.Threading.Tasks; using System.Xml; using System.Xml.Serialization; +using Microsoft.Net.Http.Headers; namespace Microsoft.AspNet.Mvc { @@ -12,14 +14,14 @@ namespace Microsoft.AspNet.Mvc /// This class handles serialization of objects /// to XML using /// - public class XmlSerializerOutputFormatter : XmlOutputFormatter + public class XmlSerializerOutputFormatter : OutputFormatter { /// /// Initializes a new instance of /// with default XmlWriterSettings. /// - public XmlSerializerOutputFormatter() - : this(GetDefaultXmlWriterSettings()) + public XmlSerializerOutputFormatter() : + this(FormattingUtilities.GetDefaultXmlWriterSettings()) { } @@ -28,8 +30,39 @@ namespace Microsoft.AspNet.Mvc /// /// The settings to be used by the . public XmlSerializerOutputFormatter([NotNull] XmlWriterSettings writerSettings) - : base(writerSettings) { + SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM); + SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian); + + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml")); + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml")); + + WriterSettings = writerSettings; + } + + /// + /// Gets the settings to be used by the XmlWriter. + /// + public XmlWriterSettings WriterSettings { get; } + + /// + /// Gets the type of the object to be serialized. + /// + /// The declared type. + /// The runtime type. + /// The type of the object to be serialized. + protected virtual Type GetSerializableType(Type declaredType, Type runtimeType) + { + if (declaredType == null || + declaredType == typeof(object)) + { + if (runtimeType != null) + { + return runtimeType; + } + } + + return declaredType; } /// @@ -58,6 +91,17 @@ namespace Microsoft.AspNet.Mvc } } + /// + /// Creates a new instance of using the given stream and the . + /// + /// The stream on which the XmlWriter should operate on. + /// A new instance of + public virtual XmlWriter CreateXmlWriter([NotNull] Stream writeStream, + [NotNull] XmlWriterSettings xmlWriterSettings) + { + return XmlWriter.Create(writeStream, xmlWriterSettings); + } + /// public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context) { diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcOptionsExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/MvcOptionsExtensions.cs index fdeb84115c..03e94f8701 100644 --- a/src/Microsoft.AspNet.Mvc.Core/MvcOptionsExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/MvcOptionsExtensions.cs @@ -13,8 +13,7 @@ namespace Microsoft.AspNet.Mvc /// The MvcOptions public static void AddXmlDataContractSerializerFormatter([NotNull] this MvcOptions options) { - options.OutputFormatters.Add( - new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings())); + options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter()); } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs index bdcd2c1258..f89b9231f3 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ObjectResultTests.cs @@ -492,7 +492,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults new HttpNoContentOutputFormatter(), new StringOutputFormatter(), new JsonOutputFormatter(), - new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings()) + new XmlDataContractSerializerOutputFormatter() }; var response = GetMockHttpResponse(); @@ -533,7 +533,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults new HttpNoContentOutputFormatter(), new StringOutputFormatter(), new JsonOutputFormatter(), - new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings()) + new XmlDataContractSerializerOutputFormatter() }; var response = GetMockHttpResponse(); @@ -568,7 +568,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults new HttpNoContentOutputFormatter(), new StringOutputFormatter(), new JsonOutputFormatter(), - new XmlDataContractSerializerOutputFormatter(XmlSerializerOutputFormatter.GetDefaultXmlWriterSettings()) + new XmlDataContractSerializerOutputFormatter() }; var response = GetMockHttpResponse(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs index fc2a71c828..bf61734604 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs @@ -84,13 +84,51 @@ namespace Microsoft.AspNet.Mvc.Core Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead); } + [Fact] + public void DefaultConstructor_ExpectedWriterSettings_Created() + { + // Arrange and Act + var formatter = new XmlDataContractSerializerOutputFormatter(); + + // Assert + var writerSettings = formatter.WriterSettings; + Assert.NotNull(writerSettings); + Assert.True(writerSettings.OmitXmlDeclaration); + Assert.False(writerSettings.CloseOutput); + Assert.False(writerSettings.CheckCharacters); + } + + [Fact] + public async Task SuppliedWriterSettings_TakeAffect() + { + // Arrange + var writerSettings = FormattingUtilities.GetDefaultXmlWriterSettings(); + writerSettings.OmitXmlDeclaration = false; + var sampleInput = new DummyClass { SampleInt = 10 }; + var formatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); + var formatter = new XmlDataContractSerializerOutputFormatter(writerSettings); + var expectedOutput = ""+ + "" + + "10"; + + // Act + await formatter.WriteAsync(formatterContext); + + // Assert + Assert.Same(writerSettings, formatter.WriterSettings); + var responseStream = formatterContext.ActionContext.HttpContext.Response.Body; + Assert.NotNull(responseStream); + responseStream.Position = 0; + var actualOutput = new StreamReader(responseStream, Encoding.UTF8).ReadToEnd(); + Assert.Equal(expectedOutput, actualOutput); + } + [Fact] public async Task XmlDataContractSerializerOutputFormatterWritesSimpleTypes() { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlDataContractSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlDataContractSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act @@ -118,8 +156,7 @@ namespace Microsoft.AspNet.Mvc.Core sampleString = "TestLevelOne string" } }; - var formatter = new XmlDataContractSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlDataContractSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act @@ -168,8 +205,7 @@ namespace Microsoft.AspNet.Mvc.Core var sampleInput = new DummyClass { SampleInt = 10 }; var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType(), "application/xml; charset=utf-16"); - var formatter = new XmlDataContractSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlDataContractSerializerOutputFormatter(); formatter.WriterSettings.OmitXmlDeclaration = false; // Act @@ -190,8 +226,7 @@ namespace Microsoft.AspNet.Mvc.Core { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlDataContractSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlDataContractSerializerOutputFormatter(); formatter.WriterSettings.Indent = true; var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); @@ -213,8 +248,7 @@ namespace Microsoft.AspNet.Mvc.Core { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlDataContractSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlDataContractSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs index b912327211..37fdeed886 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs @@ -66,13 +66,51 @@ namespace Microsoft.AspNet.Mvc.Core Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead); } + [Fact] + public void DefaultConstructor_ExpectedWriterSettings_Created() + { + // Arrange and Act + var formatter = new XmlSerializerOutputFormatter(); + + // Assert + var writerSettings = formatter.WriterSettings; + Assert.NotNull(writerSettings); + Assert.True(writerSettings.OmitXmlDeclaration); + Assert.False(writerSettings.CloseOutput); + Assert.False(writerSettings.CheckCharacters); + } + + [Fact] + public async Task SuppliedWriterSettings_TakeAffect() + { + // Arrange + var writerSettings = FormattingUtilities.GetDefaultXmlWriterSettings(); + writerSettings.OmitXmlDeclaration = false; + var sampleInput = new DummyClass { SampleInt = 10 }; + var formatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); + var formatter = new XmlSerializerOutputFormatter(writerSettings); + var expectedOutput = "" + + "10"; + + // Act + await formatter.WriteAsync(formatterContext); + + // Assert + Assert.Same(writerSettings, formatter.WriterSettings); + var responseStream = formatterContext.ActionContext.HttpContext.Response.Body; + Assert.NotNull(responseStream); + responseStream.Position = 0; + var actualOutput = new StreamReader(responseStream, Encoding.UTF8).ReadToEnd(); + Assert.Equal(expectedOutput, actualOutput); + } + [Fact] public async Task XmlSerializerOutputFormatterWritesSimpleTypes() { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act @@ -101,8 +139,7 @@ namespace Microsoft.AspNet.Mvc.Core sampleString = "TestLevelOne string" } }; - var formatter = new XmlSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act @@ -152,8 +189,7 @@ namespace Microsoft.AspNet.Mvc.Core var sampleInput = new DummyClass { SampleInt = 10 }; var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType(), "application/xml; charset=utf-16"); - var formatter = new XmlSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlSerializerOutputFormatter(); formatter.WriterSettings.OmitXmlDeclaration = false; // Act @@ -174,8 +210,7 @@ namespace Microsoft.AspNet.Mvc.Core { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlSerializerOutputFormatter(); formatter.WriterSettings.Indent = true; var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); @@ -197,8 +232,7 @@ namespace Microsoft.AspNet.Mvc.Core { // Arrange var sampleInput = new DummyClass { SampleInt = 10 }; - var formatter = new XmlSerializerOutputFormatter( - XmlOutputFormatter.GetDefaultXmlWriterSettings()); + var formatter = new XmlSerializerOutputFormatter(); var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType()); // Act