[Fixes #6197] AddXmlSerializerFormatters with no namespace
This commit is contained in:
parent
05d02e7cab
commit
d5bb73a98c
|
|
@ -203,6 +203,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
return XmlWriter.Create(writer, xmlWriterSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="XmlWriter"/> using the given <see cref="TextWriter"/> and
|
||||
/// <see cref="XmlWriterSettings"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The formatter context associated with the call.</param>
|
||||
/// <param name="writer">
|
||||
/// The underlying <see cref="TextWriter"/> which the <see cref="XmlWriter"/> should write to.
|
||||
/// </param>
|
||||
/// <param name="xmlWriterSettings">
|
||||
/// The <see cref="XmlWriterSettings"/>.
|
||||
/// </param>
|
||||
/// <returns>A new instance of <see cref="XmlWriter"/>.</returns>
|
||||
public virtual XmlWriter CreateXmlWriter(
|
||||
OutputFormatterWriteContext context,
|
||||
TextWriter writer,
|
||||
XmlWriterSettings xmlWriterSettings)
|
||||
{
|
||||
return CreateXmlWriter(writer, xmlWriterSettings);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
|
||||
{
|
||||
|
|
@ -235,7 +255,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
using (var textWriter = context.WriterFactory(context.HttpContext.Response.Body, writerSettings.Encoding))
|
||||
{
|
||||
using (var xmlWriter = CreateXmlWriter(textWriter, writerSettings))
|
||||
using (var xmlWriter = CreateXmlWriter(context, textWriter, writerSettings))
|
||||
{
|
||||
dataContractSerializer.WriteObject(xmlWriter, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
/// <param name="xmlWriterSettings">
|
||||
/// The <see cref="XmlWriterSettings"/>.
|
||||
/// </param>
|
||||
/// <returns>A new instance of <see cref="XmlWriter"/></returns>
|
||||
/// <returns>A new instance of <see cref="XmlWriter"/>.</returns>
|
||||
public virtual XmlWriter CreateXmlWriter(
|
||||
TextWriter writer,
|
||||
XmlWriterSettings xmlWriterSettings)
|
||||
|
|
@ -179,6 +179,26 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
return XmlWriter.Create(writer, xmlWriterSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="XmlWriter"/> using the given <see cref="TextWriter"/> and
|
||||
/// <see cref="XmlWriterSettings"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The formatter context associated with the call.</param>
|
||||
/// <param name="writer">
|
||||
/// The underlying <see cref="TextWriter"/> which the <see cref="XmlWriter"/> should write to.
|
||||
/// </param>
|
||||
/// <param name="xmlWriterSettings">
|
||||
/// The <see cref="XmlWriterSettings"/>.
|
||||
/// </param>
|
||||
/// <returns>A new instance of <see cref="XmlWriter"/></returns>
|
||||
public virtual XmlWriter CreateXmlWriter(
|
||||
OutputFormatterWriteContext context,
|
||||
TextWriter writer,
|
||||
XmlWriterSettings xmlWriterSettings)
|
||||
{
|
||||
return CreateXmlWriter(writer, xmlWriterSettings);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
|
||||
{
|
||||
|
|
@ -211,9 +231,9 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
using (var textWriter = context.WriterFactory(context.HttpContext.Response.Body, writerSettings.Encoding))
|
||||
{
|
||||
using (var xmlWriter = CreateXmlWriter(textWriter, writerSettings))
|
||||
using (var xmlWriter = CreateXmlWriter(context, textWriter, writerSettings))
|
||||
{
|
||||
xmlSerializer.Serialize(xmlWriter, value);
|
||||
Serialize(xmlSerializer, xmlWriter, value);
|
||||
}
|
||||
|
||||
// Perf: call FlushAsync to call WriteAsync on the stream with any content left in the TextWriter's
|
||||
|
|
@ -223,6 +243,18 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes value using the passed in <paramref name="xmlSerializer"/> and <paramref name="xmlWriter"/>.
|
||||
/// </summary>
|
||||
/// <param name="xmlSerializer">The serializer used to serialize the <paramref name="value"/>.</param>
|
||||
/// <param name="xmlWriter">The writer used by the serializer <paramref name="xmlSerializer"/>
|
||||
/// to serialize the <paramref name="value"/>.</param>
|
||||
/// <param name="value">The value to be serialized.</param>
|
||||
protected virtual void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
|
||||
{
|
||||
xmlSerializer.Serialize(xmlWriter, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cached serializer or creates and caches the serializer for the given type.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// 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;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
|
|
@ -11,11 +13,20 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
{
|
||||
public static Stream GetThrowingStream()
|
||||
{
|
||||
var mock = new Mock<Stream>();
|
||||
mock.Verify(m => m.Flush(), Times.Never());
|
||||
mock.Verify(m => m.FlushAsync(It.IsAny<CancellationToken>()), Times.Never());
|
||||
return new NonFlushingStream();
|
||||
}
|
||||
|
||||
return mock.Object;
|
||||
private class NonFlushingStream : MemoryStream
|
||||
{
|
||||
public override void Flush()
|
||||
{
|
||||
throw new InvalidOperationException("Flush should not have been called.");
|
||||
}
|
||||
|
||||
public override Task FlushAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
throw new InvalidOperationException("FlushAsync should not have been called.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -682,6 +682,42 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
Assert.False(canWriteResult);
|
||||
}
|
||||
|
||||
public static TheoryData<bool, object, string> CanIndentOutputConditionallyData
|
||||
{
|
||||
get
|
||||
{
|
||||
var obj = new DummyClass { SampleInt = 10 };
|
||||
var newLine = Environment.NewLine;
|
||||
return new TheoryData<bool, object, string>()
|
||||
{
|
||||
{ true, obj, "<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
|
||||
$"{newLine} <SampleInt>10</SampleInt>{newLine}</DummyClass>" },
|
||||
{ false, obj, "<DummyClass xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">" +
|
||||
"<SampleInt>10</SampleInt></DummyClass>" }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CanIndentOutputConditionallyData))]
|
||||
public async Task CanIndentOutputConditionally(bool indent, object input, string expectedOutput)
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new IndentingXmlDataContractSerializerOutputFormatter();
|
||||
var outputFormatterContext = GetOutputFormatterContext(input, input.GetType());
|
||||
outputFormatterContext.HttpContext.Request.QueryString = new QueryString("?indent=" + indent);
|
||||
|
||||
// Act
|
||||
await formatter.WriteAsync(outputFormatterContext);
|
||||
|
||||
// Assert
|
||||
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||
body.Position = 0;
|
||||
|
||||
var content = new StreamReader(body).ReadToEnd();
|
||||
Assert.Equal(expectedOutput, content);
|
||||
}
|
||||
|
||||
private OutputFormatterWriteContext GetOutputFormatterContext(
|
||||
object outputValue,
|
||||
Type outputType,
|
||||
|
|
@ -696,20 +732,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
|
||||
private static HttpContext GetHttpContext(string contentType)
|
||||
{
|
||||
var request = new Mock<HttpRequest>();
|
||||
|
||||
var headers = new HeaderDictionary();
|
||||
headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset.ToString();
|
||||
request.Setup(r => r.ContentType).Returns(contentType);
|
||||
request.SetupGet(r => r.Headers).Returns(headers);
|
||||
|
||||
var response = new Mock<HttpResponse>();
|
||||
response.SetupGet(f => f.Body).Returns(new MemoryStream());
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.Request).Returns(request.Object);
|
||||
httpContext.SetupGet(c => c.Response).Returns(response.Object);
|
||||
return httpContext.Object;
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var request = httpContext.Request;
|
||||
request.Headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset.ToString();
|
||||
request.ContentType = contentType;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private class TestXmlDataContractSerializerOutputFormatter : XmlDataContractSerializerOutputFormatter
|
||||
|
|
@ -723,6 +751,22 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
}
|
||||
}
|
||||
|
||||
private class IndentingXmlDataContractSerializerOutputFormatter : XmlDataContractSerializerOutputFormatter
|
||||
{
|
||||
public override XmlWriter CreateXmlWriter(
|
||||
OutputFormatterWriteContext context,
|
||||
TextWriter writer,
|
||||
XmlWriterSettings xmlWriterSettings)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
if (request.Query["indent"] == "True")
|
||||
{
|
||||
xmlWriterSettings.Indent = true;
|
||||
}
|
||||
|
||||
return base.CreateXmlWriter(context, writer, xmlWriterSettings);
|
||||
}
|
||||
}
|
||||
public class Customer
|
||||
{
|
||||
public Customer(int id)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
|||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
|
|
@ -71,6 +72,62 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
XmlAssert.Equal(expectedOutput, content);
|
||||
}
|
||||
|
||||
public static TheoryData<bool, object, string> CanIndentOutputConditionallyData
|
||||
{
|
||||
get
|
||||
{
|
||||
var obj = new DummyClass { SampleInt = 10 };
|
||||
var newLine = Environment.NewLine;
|
||||
return new TheoryData<bool, object, string>()
|
||||
{
|
||||
{ true, obj, "<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
|
||||
$"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">{newLine} <SampleInt>10</SampleInt>{newLine}</DummyClass>" },
|
||||
{ false, obj, "<DummyClass xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
|
||||
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><SampleInt>10</SampleInt></DummyClass>" }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CanIndentOutputConditionallyData))]
|
||||
public async Task XmlSerializer_CanIndentOutputConditionally(bool indent, object input, string expectedOutput)
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new IndentingXmlSerializerOutputFormatter();
|
||||
var outputFormatterContext = GetOutputFormatterContext(input, input.GetType());
|
||||
outputFormatterContext.HttpContext.Request.QueryString = new QueryString("?indent=" + indent);
|
||||
|
||||
// Act
|
||||
await formatter.WriteAsync(outputFormatterContext);
|
||||
|
||||
// Assert
|
||||
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||
body.Position = 0;
|
||||
|
||||
var content = new StreamReader(body).ReadToEnd();
|
||||
Assert.Equal(expectedOutput, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task XmlSerializer_CanModifyNamespacesInGeneratedXml()
|
||||
{
|
||||
// Arrange
|
||||
var input = new DummyClass { SampleInt = 10 };
|
||||
var formatter = new IgnoreAmbientNamespacesXmlSerializerOutputFormatter();
|
||||
var outputFormatterContext = GetOutputFormatterContext(input, input.GetType());
|
||||
var expectedOutput = "<DummyClass><SampleInt>10</SampleInt></DummyClass>";
|
||||
|
||||
// Act
|
||||
await formatter.WriteAsync(outputFormatterContext);
|
||||
|
||||
// Assert
|
||||
var body = outputFormatterContext.HttpContext.Response.Body;
|
||||
body.Position = 0;
|
||||
|
||||
var content = new StreamReader(body).ReadToEnd();
|
||||
Assert.Equal(expectedOutput, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void XmlSerializer_CachesSerializerForType()
|
||||
{
|
||||
|
|
@ -461,20 +518,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
|
||||
private static HttpContext GetHttpContext(string contentType)
|
||||
{
|
||||
var request = new Mock<HttpRequest>();
|
||||
|
||||
var headers = new HeaderDictionary();
|
||||
headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset.ToString();
|
||||
request.Setup(r => r.ContentType).Returns(contentType);
|
||||
request.SetupGet(r => r.Headers).Returns(headers);
|
||||
|
||||
var response = new Mock<HttpResponse>();
|
||||
response.SetupGet(f => f.Body).Returns(new MemoryStream());
|
||||
|
||||
var httpContext = new Mock<HttpContext>();
|
||||
httpContext.SetupGet(c => c.Request).Returns(request.Object);
|
||||
httpContext.SetupGet(c => c.Response).Returns(response.Object);
|
||||
return httpContext.Object;
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var request = httpContext.Request;
|
||||
request.Headers["Accept-Charset"] = MediaTypeHeaderValue.Parse(contentType).Charset.ToString();
|
||||
request.ContentType = contentType;
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private class TestXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
|
||||
|
|
@ -496,5 +545,32 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
|
||||
public int MyProperty { get; set; }
|
||||
}
|
||||
private class IndentingXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
|
||||
{
|
||||
public override XmlWriter CreateXmlWriter(
|
||||
OutputFormatterWriteContext context,
|
||||
TextWriter writer,
|
||||
XmlWriterSettings xmlWriterSettings)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
if (request.Query["indent"] == "True")
|
||||
{
|
||||
xmlWriterSettings.Indent = true;
|
||||
}
|
||||
|
||||
return base.CreateXmlWriter(context, writer, xmlWriterSettings);
|
||||
}
|
||||
}
|
||||
|
||||
private class IgnoreAmbientNamespacesXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
|
||||
{
|
||||
protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
|
||||
{
|
||||
var namespaces = new XmlSerializerNamespaces();
|
||||
namespaces.Add("", "");
|
||||
|
||||
xmlSerializer.Serialize(xmlWriter, value, namespaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue