diff --git a/Mvc.sln b/Mvc.sln
index e476c49ffc..0a7055d74d 100644
--- a/Mvc.sln
+++ b/Mvc.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.21902.1
+VisualStudioVersion = 14.0.22013.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@@ -67,7 +67,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
global.json = global.json
EndProjectSection
+EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ConnegWebsite", "test\WebSites\ConnegWebSite\ConnegWebsite.kproj", "{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}"
+EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AntiForgeryWebSite", "test\WebSites\AntiForgeryWebSite\AntiForgeryWebSite.kproj", "{A353B17E-A940-4CE8-8BF9-179E24A9041F}"
EndProject
Global
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs
new file mode 100644
index 0000000000..efc07b7c2c
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlDataContractSerializerOutputFormatter.cs
@@ -0,0 +1,61 @@
+// 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.Runtime.Serialization;
+using System.Threading.Tasks;
+using System.Xml;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// This class handles serialization of objects
+ /// to XML using
+ ///
+ public class XmlDataContractSerializerOutputFormatter : XmlOutputFormatter
+ {
+ ///
+ /// Initializes a new instance of
+ /// with default XmlWriterSettings
+ ///
+ public XmlDataContractSerializerOutputFormatter()
+ :this(GetDefaultXmlWriterSettings())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of
+ ///
+ /// The settings to be used by the .
+ public XmlDataContractSerializerOutputFormatter([NotNull] XmlWriterSettings writerSettings)
+ :base(writerSettings)
+ {
+ }
+
+ ///
+ /// Create a new instance of for the given object type.
+ ///
+ /// The type of object for which the serializer should be created.
+ /// A new instance of
+ public virtual DataContractSerializer CreateDataContractSerializer([NotNull] Type type)
+ {
+ return new DataContractSerializer(type);
+ }
+
+ ///
+ public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context)
+ {
+ var response = context.ActionContext.HttpContext.Response;
+
+ var tempWriterSettings = WriterSettings.Clone();
+ tempWriterSettings.Encoding = context.SelectedEncoding;
+ using (var xmlWriter = CreateXmlWriter(response.Body, tempWriterSettings))
+ {
+ var dataContractSerializer = CreateDataContractSerializer(context.DeclaredType);
+ dataContractSerializer.WriteObject(xmlWriter, context.Object);
+ }
+
+ return Task.FromResult(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs
new file mode 100644
index 0000000000..53dc95bfe5
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlOutputFormatter.cs
@@ -0,0 +1,55 @@
+// 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.IO;
+using System.Xml;
+using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
+
+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 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
new file mode 100644
index 0000000000..e74dc5db2d
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/XmlSerializerOutputFormatter.cs
@@ -0,0 +1,61 @@
+// 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.Threading.Tasks;
+using System.Xml;
+using System.Xml.Serialization;
+
+namespace Microsoft.AspNet.Mvc
+{
+ ///
+ /// This class handles serialization of objects
+ /// to XML using
+ ///
+ public class XmlSerializerOutputFormatter : XmlOutputFormatter
+ {
+ ///
+ /// Initializes a new instance of
+ /// with default XmlWriterSettings.
+ ///
+ public XmlSerializerOutputFormatter()
+ :this(GetDefaultXmlWriterSettings())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of
+ ///
+ /// The settings to be used by the .
+ public XmlSerializerOutputFormatter([NotNull] XmlWriterSettings writerSettings)
+ :base(writerSettings)
+ {
+ }
+
+ ///
+ /// Create a new instance of for the given object type.
+ ///
+ /// The type of object for which the serializer should be created.
+ /// A new instance of
+ public virtual XmlSerializer CreateXmlSerializer([NotNull] Type type)
+ {
+ return new XmlSerializer(type);
+ }
+
+ ///
+ public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context)
+ {
+ var response = context.ActionContext.HttpContext.Response;
+
+ var tempWriterSettings = WriterSettings.Clone();
+ tempWriterSettings.Encoding = context.SelectedEncoding;
+ using (var xmlWriter = CreateXmlWriter(response.Body, tempWriterSettings))
+ {
+ var xmlSerializer = CreateXmlSerializer(context.DeclaredType);
+ xmlSerializer.Serialize(xmlWriter, context.Object);
+ }
+
+ return Task.FromResult(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
index c1f3ddf6c7..f6c7f634e4 100644
--- a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
+++ b/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs
@@ -38,6 +38,10 @@ namespace Microsoft.AspNet.Mvc
options.OutputFormatters.Add(new TextPlainFormatter());
options.OutputFormatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(),
indent: false));
+ options.OutputFormatters.Add(
+ new XmlDataContractSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
+ options.OutputFormatters.Add(
+ new XmlSerializerOutputFormatter(XmlOutputFormatter.GetDefaultXmlWriterSettings()));
// Set up ValueProviders
options.ValueProviderFactories.Add(new RouteValueValueProviderFactory());
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs
new file mode 100644
index 0000000000..2370d00b66
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlDataContractSerializerOutputFormatterTests.cs
@@ -0,0 +1,209 @@
+// 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.Runtime.Serialization;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.Core
+{
+ public class XmlDataContractSerializerOutputFormatterTests
+ {
+ [DataContract(Name = "DummyClass", Namespace = "")]
+ public class DummyClass
+ {
+ [DataMember]
+ public int SampleInt { get; set; }
+ }
+
+ [DataContract(Name = "TestLevelOne", Namespace = "")]
+ public class TestLevelOne
+ {
+ [DataMember]
+ public int SampleInt { get; set; }
+ [DataMember]
+ public string sampleString;
+ }
+
+ [DataContract(Name = "TestLevelTwo", Namespace = "")]
+ public class TestLevelTwo
+ {
+ [DataMember]
+ public string SampleString { get; set; }
+ [DataMember]
+ public TestLevelOne TestOne { get; set; }
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterWritesSimpleTypes()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
+ .ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterWritesComplexTypes()
+ {
+ // Arrange
+ var sampleInput = new TestLevelTwo
+ {
+ SampleString = "TestString",
+ TestOne = new TestLevelOne
+ {
+ SampleInt = 10,
+ sampleString = "TestLevelOne string"
+ }
+ };
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "TestString" +
+ "10TestLevelOne string" +
+ "",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
+ .ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterWritesOnModifiedWriterSettings()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ new System.Xml.XmlWriterSettings
+ {
+ OmitXmlDeclaration = false,
+ CloseOutput = false
+ });
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8).ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterWritesUTF16Output()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType(),
+ "application/xml; charset=utf-16");
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ formatter.WriterSettings.OmitXmlDeclaration = false;
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
+ Encodings.UTF16EncodingLittleEndian).ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterWritesIndentedOutput()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ formatter.WriterSettings.Indent = true;
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ var outputString = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
+ Encoding.UTF8).ReadToEnd();
+ Assert.Equal("" +
+ "\r\n 10\r\n",
+ outputString);
+ }
+
+ [Fact]
+ public async Task VerifyBodyIsNotClosedAfterOutputIsWritten()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlDataContractSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
+ }
+
+ private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType,
+ string contentType = "application/xml; charset=utf-8")
+ {
+ return new OutputFormatterContext
+ {
+ Object = outputValue,
+ DeclaredType = outputType,
+ ActionContext = GetActionContext(contentType)
+ };
+ }
+
+ private static ActionContext GetActionContext(string contentType)
+ {
+ var request = new Mock();
+ var headers = new Mock();
+ request.Setup(r => r.ContentType).Returns(contentType);
+ request.SetupGet(r => r.Headers).Returns(headers.Object);
+ request.SetupGet(f => f.AcceptCharset).Returns(contentType.Split('=')[1]);
+ var response = new Mock();
+ response.SetupGet(f => f.Body).Returns(new MemoryStream());
+ var httpContext = new Mock();
+ httpContext.SetupGet(c => c.Request).Returns(request.Object);
+ httpContext.SetupGet(c => c.Response).Returns(response.Object);
+ return new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs
new file mode 100644
index 0000000000..2ffd2ab87f
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Formatters/XmlSerializerOutputFormatterTests.cs
@@ -0,0 +1,202 @@
+// 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.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.Core
+{
+ public class XmlSerializerOutputFormatterTests
+ {
+ public class DummyClass
+ {
+ public int SampleInt { get; set; }
+ }
+
+ public class TestLevelOne
+ {
+ public int SampleInt { get; set; }
+ public string sampleString;
+ }
+
+ public class TestLevelTwo
+ {
+ public string SampleString { get; set; }
+ public TestLevelOne TestOne { get; set; }
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterWritesSimpleTypes()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
+ .ReadToEnd());
+ Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterWritesComplexTypes()
+ {
+ // Arrange
+ var sampleInput = new TestLevelTwo
+ {
+ SampleString = "TestString",
+ TestOne = new TestLevelOne
+ {
+ SampleInt = 10,
+ sampleString = "TestLevelOne string"
+ }
+ };
+ var formatter = new XmlSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("TestString" +
+ "TestLevelOne string" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
+ .ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterWritesOnModifiedWriterSettings()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+ var formatter = new XmlSerializerOutputFormatter(
+ new System.Xml.XmlWriterSettings
+ {
+ OmitXmlDeclaration = false,
+ CloseOutput = false
+ });
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body, Encoding.UTF8)
+ .ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterWritesUTF16Output()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var outputFormatterContext =
+ GetOutputFormatterContext(sampleInput, sampleInput.GetType(), "application/xml; charset=utf-16");
+ var formatter = new XmlSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ formatter.WriterSettings.OmitXmlDeclaration = false;
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ Assert.Equal("" +
+ "10",
+ new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
+ Encodings.UTF16EncodingLittleEndian).ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterWritesIndentedOutput()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ formatter.WriterSettings.Indent = true;
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ outputFormatterContext.ActionContext.HttpContext.Response.Body.Position = 0;
+ var outputString = new StreamReader(outputFormatterContext.ActionContext.HttpContext.Response.Body,
+ Encoding.UTF8).ReadToEnd();
+ Assert.Equal("\r\n 10\r\n",
+ outputString);
+ }
+
+ [Fact]
+ public async Task VerifyBodyIsNotClosedAfterOutputIsWritten()
+ {
+ // Arrange
+ var sampleInput = new DummyClass { SampleInt = 10 };
+ var formatter = new XmlSerializerOutputFormatter(
+ XmlOutputFormatter.GetDefaultXmlWriterSettings());
+ var outputFormatterContext = GetOutputFormatterContext(sampleInput, sampleInput.GetType());
+
+ // Act
+ await formatter.WriteAsync(outputFormatterContext);
+
+ // Assert
+ Assert.NotNull(outputFormatterContext.ActionContext.HttpContext.Response.Body);
+ Assert.True(outputFormatterContext.ActionContext.HttpContext.Response.Body.CanRead);
+ }
+
+ private OutputFormatterContext GetOutputFormatterContext(object outputValue, Type outputType,
+ string contentType = "application/xml; charset=utf-8")
+ {
+ return new OutputFormatterContext
+ {
+ Object = outputValue,
+ DeclaredType = outputType,
+ ActionContext = GetActionContext(contentType)
+ };
+ }
+
+ private static ActionContext GetActionContext(string contentType)
+ {
+ var request = new Mock();
+ var headers = new Mock();
+ request.Setup(r => r.ContentType).Returns(contentType);
+ request.SetupGet(r => r.Headers).Returns(headers.Object);
+ request.SetupGet(f => f.AcceptCharset).Returns(contentType.Split('=')[1]);
+ var response = new Mock();
+ response.SetupGet(f => f.Body).Returns(new MemoryStream());
+ var httpContext = new Mock();
+ httpContext.SetupGet(c => c.Request).Returns(request.Object);
+ httpContext.SetupGet(c => c.Response).Returns(response.Object);
+ return new ActionContext(httpContext.Object, routeData: null, actionDescriptor: null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlOutputFormatterTests.cs
new file mode 100644
index 0000000000..35d74ef7e3
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlOutputFormatterTests.cs
@@ -0,0 +1,66 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Builder;
+using Microsoft.AspNet.TestHost;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.FunctionalTests
+{
+ public class XmlOutputFormatterTests
+ {
+ private readonly IServiceProvider _services;
+ private readonly Action _app = new FormatterWebSite.Startup().Configure;
+
+ public XmlOutputFormatterTests()
+ {
+ _services = TestHelper.CreateServices("FormatterWebSite");
+ }
+
+ [Fact]
+ public async Task XmlDataContractSerializerOutputFormatterIsCalled()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+ var headers = new Dictionary();
+ headers.Add("Accept", new string[] { "application/xml;charset=utf-8" });
+
+ // Act
+ var response = await client.SendAsync("POST",
+ "http://localhost/Home/GetDummyClass?sampleInput=10", headers, null, null);
+
+ //Assert
+ Assert.Equal(200, response.StatusCode);
+ Assert.Equal("" +
+ "10",
+ new StreamReader(response.Body, Encoding.UTF8).ReadToEnd());
+ }
+
+ [Fact]
+ public async Task XmlSerializerOutputFormatterIsCalled()
+ {
+ // Arrange
+ var server = TestServer.Create(_services, _app);
+ var client = server.Handler;
+ var headers = new Dictionary();
+ headers.Add("Accept", new string[] { "application/xml;charset=utf-8" });
+
+ // Act
+ var response = await client.SendAsync("POST",
+ "http://localhost/XmlSerializer/GetDummyClass?sampleInput=10", headers, null, null);
+
+ //Assert
+ Assert.Equal(200, response.StatusCode);
+ Assert.Equal("10",
+ new StreamReader(response.Body, Encoding.UTF8).ReadToEnd());
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs b/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
index 7435777fb6..57daadadcf 100644
--- a/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Test/MvcOptionSetupTest.cs
@@ -73,10 +73,12 @@ namespace Microsoft.AspNet.Mvc
setup.Setup(mvcOptions);
// Assert
- Assert.Equal(3, mvcOptions.OutputFormatters.Count);
+ Assert.Equal(5, mvcOptions.OutputFormatters.Count);
Assert.IsType(mvcOptions.OutputFormatters[0].Instance);
Assert.IsType(mvcOptions.OutputFormatters[1].Instance);
Assert.IsType(mvcOptions.OutputFormatters[2].Instance);
+ Assert.IsType(mvcOptions.OutputFormatters[3].Instance);
+ Assert.IsType(mvcOptions.OutputFormatters[4].Instance);
}
}
}
\ No newline at end of file
diff --git a/test/WebSites/FormatterWebSite/Controllers/HomeController.cs b/test/WebSites/FormatterWebSite/Controllers/HomeController.cs
index 873094da3a..e8d8f0cdaf 100644
--- a/test/WebSites/FormatterWebSite/Controllers/HomeController.cs
+++ b/test/WebSites/FormatterWebSite/Controllers/HomeController.cs
@@ -12,5 +12,11 @@ namespace FormatterWebSite.Controllers
{
return Content(dummyObject.SampleInt.ToString());
}
+
+ [HttpPost]
+ public DummyClass GetDummyClass(int sampleInput)
+ {
+ return new DummyClass { SampleInt = sampleInput };
+ }
}
}
\ No newline at end of file
diff --git a/test/WebSites/FormatterWebSite/Controllers/XmlSerializerController.cs b/test/WebSites/FormatterWebSite/Controllers/XmlSerializerController.cs
new file mode 100644
index 0000000000..0a0c154ad5
--- /dev/null
+++ b/test/WebSites/FormatterWebSite/Controllers/XmlSerializerController.cs
@@ -0,0 +1,27 @@
+// 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 Microsoft.AspNet.Mvc;
+
+namespace FormatterWebSite
+{
+ public class XmlSerializerController : Controller
+ {
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ var result = context.Result as ObjectResult;
+ if (result != null)
+ {
+ result.Formatters.Add(new XmlSerializerOutputFormatter());
+ }
+
+ base.OnActionExecuted(context);
+ }
+
+ [HttpPost]
+ public DummyClass GetDummyClass(int sampleInput)
+ {
+ return new DummyClass { SampleInt = sampleInput };
+ }
+ }
+}
\ No newline at end of file