1. Introducing XML Input Formatters.

2. Adding DelegatingStream class
3. Unit + Functional tests for formatters.
This commit is contained in:
sornaks 2014-07-01 17:11:49 -07:00
parent 43d1253936
commit cee73c0af3
24 changed files with 1395 additions and 11 deletions

13
Mvc.sln
View File

@ -54,6 +54,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CompositeViewEngine", "test
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorWebSite", "test\WebSites\RazorWebSite\RazorWebSite.kproj", "{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatterWebSite", "test\WebSites\FormatterWebSite\FormatterWebSite.kproj", "{62735776-46FF-4170-9392-02E128A69B89}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ValueProvidersSite", "test\WebSites\ValueProvidersSite\ValueProvidersSite.kproj", "{14F79E79-AE79-48FA-95DE-D794EF4EABB3}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.HeaderValueAbstractions", "src\Microsoft.AspNet.Mvc.HeaderValueAbstractions\Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj", "{98335B23-E4B9-4CAD-9749-0DED32A659A1}"
EndProject
@ -279,6 +281,16 @@ Global
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78}.Release|x86.ActiveCfg = Release|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Debug|x86.ActiveCfg = Debug|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Release|Any CPU.Build.0 = Release|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{62735776-46FF-4170-9392-02E128A69B89}.Release|x86.ActiveCfg = Release|Any CPU
{14F79E79-AE79-48FA-95DE-D794EF4EABB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14F79E79-AE79-48FA-95DE-D794EF4EABB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14F79E79-AE79-48FA-95DE-D794EF4EABB3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -336,6 +348,7 @@ Global
{5F945B82-FE5F-425C-956C-8BC2F2020254} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{A853B2BA-4449-4908-A416-5A3C027FC22B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{B07CAF59-11ED-40E3-A5DB-E1178F84FA78} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{62735776-46FF-4170-9392-02E128A69B89} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{14F79E79-AE79-48FA-95DE-D794EF4EABB3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{98335B23-E4B9-4CAD-9749-0DED32A659A1} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{E69FD235-2042-43A4-9970-59CB29955B4E} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}

View File

@ -16,8 +16,7 @@ namespace Microsoft.AspNet.Mvc
/// <summary>
/// Returns UTF16 Encoding which uses littleEndian byte order with BOM and throws on invalid bytes.
/// </summary>
public static readonly Encoding UnicodeEncodingWithBOM = new UnicodeEncoding(bigEndian: false,
byteOrderMark: true,
throwOnInvalidBytes: true);
public static readonly Encoding UTF16EncodingLittleEndian
= new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true);
}
}

View File

@ -23,7 +23,7 @@ namespace Microsoft.AspNet.Mvc
_settings = settings;
_indent = indent;
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
SupportedEncodings.Add(Encodings.UnicodeEncodingWithBOM);
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json"));
}

View File

@ -18,7 +18,11 @@
"Newtonsoft.Json": "5.0.8"
},
"frameworks": {
"net45": {},
"net45": {
"dependencies": {
"System.Xml": ""
}
},
"k10": {
"dependencies": {
"Microsoft.CSharp": "4.0.0.0",
@ -41,13 +45,16 @@
"System.Runtime": "4.0.20.0",
"System.Runtime.Extensions": "4.0.10.0",
"System.Runtime.InteropServices": "4.0.20.0",
"System.Runtime.Serialization.Xml": "4.0.0.0",
"System.Security.Claims": "1.0.0-*",
"System.Security.Cryptography.Encryption": "4.0.0.0",
"System.Security.Cryptography.Hashing.Algorithms": "4.0.0.0",
"System.Security.Principal": "4.0.0.0",
"System.Text.Encoding": "4.0.20.0",
"System.Threading": "4.0.0.0",
"System.Threading.Tasks": "4.0.10.0"
"System.Threading.Tasks": "4.0.10.0",
"System.Xml.ReaderWriter": "4.0.0.0",
"System.Xml.XmlSerializer": "4.0.0.0"
}
}
}

View File

@ -0,0 +1,189 @@
// 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.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Stream that delegates to an inner stream.
/// This Stream is present so that the inner stream is not closed
/// even when Close() or Dispose() is called.
/// </summary>
public class DelegatingStream : Stream
{
private readonly Stream _innerStream;
/// <summary>
/// Initializes a new object of DelegatingStream
/// </summary>
/// <param name="innerStream">The stream on which should not be closed</param>
public DelegatingStream([NotNull] Stream innerStream)
{
_innerStream = innerStream;
}
protected Stream InnerStream
{
get { return _innerStream; }
}
/// <inheritdoc />
public override bool CanRead
{
get { return _innerStream.CanRead; }
}
/// <inheritdoc />
public override bool CanSeek
{
get { return _innerStream.CanSeek; }
}
/// <inheritdoc />
public override bool CanWrite
{
get { return _innerStream.CanWrite; }
}
/// <inheritdoc />
public override long Length
{
get { return _innerStream.Length; }
}
/// <inheritdoc />
public override long Position
{
get { return _innerStream.Position; }
set { _innerStream.Position = value; }
}
/// <inheritdoc />
public override int ReadTimeout
{
get { return _innerStream.ReadTimeout; }
set { _innerStream.ReadTimeout = value; }
}
/// <inheritdoc />
public override bool CanTimeout
{
get { return _innerStream.CanTimeout; }
}
/// <inheritdoc />
public override int WriteTimeout
{
get { return _innerStream.WriteTimeout; }
set { _innerStream.WriteTimeout = value; }
}
/// <inheritdoc />
public override long Seek(long offset, SeekOrigin origin)
{
return _innerStream.Seek(offset, origin);
}
/// <inheritdoc />
public override int Read(byte[] buffer, int offset, int count)
{
return _innerStream.Read(buffer, offset, count);
}
/// <inheritdoc />
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _innerStream.ReadAsync(buffer, offset, count, cancellationToken);
}
#if NET45
/// <inheritdoc />
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
AsyncCallback callback, object state)
{
return _innerStream.BeginRead(buffer, offset, count, callback, state);
}
/// <inheritdoc />
public override int EndRead(IAsyncResult asyncResult)
{
return _innerStream.EndRead(asyncResult);
}
#endif
/// <inheritdoc />
public override int ReadByte()
{
return _innerStream.ReadByte();
}
/// <inheritdoc />
public override void Flush()
{
_innerStream.Flush();
}
/// <inheritdoc />
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
return _innerStream.CopyToAsync(destination, bufferSize, cancellationToken);
}
/// <inheritdoc />
public override Task FlushAsync(CancellationToken cancellationToken)
{
return _innerStream.FlushAsync(cancellationToken);
}
/// <inheritdoc />
public override void SetLength(long value)
{
_innerStream.SetLength(value);
}
/// <inheritdoc />
public override void Write(byte[] buffer, int offset, int count)
{
_innerStream.Write(buffer, offset, count);
}
/// <inheritdoc />
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
}
#if NET45
/// <inheritdoc />
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
AsyncCallback callback, object state)
{
return _innerStream.BeginWrite(buffer, offset, count, callback, state);
}
/// <inheritdoc />
public override void EndWrite(IAsyncResult asyncResult)
{
_innerStream.EndWrite(asyncResult);
}
#endif
/// <inheritdoc />
public override void WriteByte(byte value)
{
_innerStream.WriteByte(value);
}
#if NET45
/// <inheritdoc />
public override void Close()
{
}
#endif
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
// No-op. In CoreCLR this is equivalent to Close.
// Given that we don't own the underlying stream, we never want to do anything interesting here.
}
}
}

View File

@ -0,0 +1,68 @@
// 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.Text;
using System.Xml;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// Contains methods which are used by input formatters.
/// </summary>
public static class FormattingUtilities
{
public static readonly int DefaultMaxDepth = 32;
/// <summary>
/// Gets the default Reader Quotas for XmlReader.
/// </summary>
/// <returns>XmlReaderQuotas with default values</returns>
public static XmlDictionaryReaderQuotas GetDefaultXmlReaderQuotas()
{
#if NET45
return new XmlDictionaryReaderQuotas()
{
MaxArrayLength = Int32.MaxValue,
MaxBytesPerRead = Int32.MaxValue,
MaxDepth = DefaultMaxDepth,
MaxNameTableCharCount = Int32.MaxValue,
MaxStringContentLength = Int32.MaxValue
};
#else
return XmlDictionaryReaderQuotas.Max;
#endif
}
/// Internal because ContentTypeHeaderValue is internal.
internal static Encoding SelectCharacterEncoding(IList<Encoding> supportedEncodings,
ContentTypeHeaderValue contentType, Type callerType)
{
if (contentType != null)
{
// Find encoding based on content type charset parameter
var charset = contentType.CharSet;
if (!string.IsNullOrWhiteSpace(contentType.CharSet))
{
for (var i = 0; i < supportedEncodings.Count; i++)
{
var supportedEncoding = supportedEncodings[i];
if (string.Equals(charset, supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase))
{
return supportedEncoding;
}
}
}
}
if (supportedEncodings.Count > 0)
{
return supportedEncodings[0];
}
// No supported encoding was found so there is no way for us to start reading.
throw new InvalidOperationException(Resources.FormatMediaTypeFormatterNoEncoding(callerType.FullName));
}
}
}

View File

@ -0,0 +1,136 @@
// 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.Reflection;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// This class handles deserialization of input XML data
/// to strongly-typed objects using <see cref="DataContractSerializer"/>.
/// </summary>
public class XmlDataContractSerializerInputFormatter : IInputFormatter
{
private readonly IList<Encoding> _supportedEncodings;
private readonly IList<string> _supportedMediaTypes;
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
/// <summary>
/// Initializes a new instance of DataContractSerializerInputFormatter
/// </summary>
public XmlDataContractSerializerInputFormatter()
{
_supportedMediaTypes = new List<string>
{
"application/xml",
"text/xml"
};
_supportedEncodings = new List<Encoding>
{
Encodings.UTF8EncodingWithoutBOM,
Encodings.UTF16EncodingLittleEndian
};
}
/// <summary>
/// Returns the list of supported encodings.
/// </summary>
public IList<Encoding> SupportedEncodings
{
get { return _supportedEncodings; }
}
/// <summary>
/// Returns the list of supported Media Types.
/// </summary>
public IList<string> SupportedMediaTypes
{
get { return _supportedMediaTypes; }
}
/// <summary>
/// Indicates the acceptable input XML depth.
/// </summary>
public int MaxDepth
{
get { return _readerQuotas.MaxDepth; }
set { _readerQuotas.MaxDepth = value; }
}
/// <summary>
/// The quotas include - DefaultMaxDepth, DefaultMaxStringContentLength, DefaultMaxArrayLength,
/// DefaultMaxBytesPerRead, DefaultMaxNameTableCharCount
/// </summary>
public XmlDictionaryReaderQuotas XmlDictionaryReaderQuotas
{
get { return _readerQuotas; }
}
/// <summary>
/// Reads the input XML.
/// </summary>
/// <param name="context">The input formatter context which contains the body to be read.</param>
/// <returns>Task which reads the input.</returns>
public async Task ReadAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
if (request.ContentLength == 0)
{
context.Model = GetDefaultValueForType(context.Metadata.ModelType);
return;
}
context.Model = await ReadInternal(context);
}
/// <summary>
/// Called during deserialization to get the <see cref="XmlReader"/>.
/// </summary>
/// <param name="readStream">The <see cref="Stream"/> from which to read.</param>
/// <returns>The <see cref="XmlReader"/> used during deserialization.</returns>
protected virtual XmlReader CreateXmlReader([NotNull] Stream readStream)
{
return XmlDictionaryReader.CreateTextReader(
readStream, _readerQuotas);
}
/// <summary>
/// Called during deserialization to get the <see cref="XmlObjectSerializer"/>.
/// </summary>
/// <returns>The <see cref="XmlObjectSerializer"/> used during deserialization.</returns>
protected virtual XmlObjectSerializer CreateDataContractSerializer(Type type)
{
return new DataContractSerializer(type);
}
private object GetDefaultValueForType(Type modelType)
{
if (modelType.GetTypeInfo().IsValueType)
{
return Activator.CreateInstance(modelType);
}
return null;
}
private Task<object> ReadInternal(InputFormatterContext context)
{
var type = context.Metadata.ModelType;
var request = context.HttpContext.Request;
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
{
var xmlSerializer = CreateDataContractSerializer(type);
return Task.FromResult(xmlSerializer.ReadObject(xmlReader));
}
}
}
}

View File

@ -0,0 +1,136 @@
// 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.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
/// <summary>
/// This class handles deserialization of input XML data
/// to strongly-typed objects using <see cref="XmlSerializer"/>
/// </summary>
public class XmlSerializerInputFormatter : IInputFormatter
{
private readonly IList<Encoding> _supportedEncodings;
private readonly IList<string> _supportedMediaTypes;
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
/// <summary>
/// Initializes a new instance of XmlSerializerInputFormatter.
/// </summary>
public XmlSerializerInputFormatter()
{
_supportedMediaTypes = new List<string>
{
"application/xml",
"text/xml"
};
_supportedEncodings = new List<Encoding>
{
Encodings.UTF8EncodingWithoutBOM,
Encodings.UTF16EncodingLittleEndian
};
}
/// <summary>
/// Returns the list of supported encodings.
/// </summary>
public IList<Encoding> SupportedEncodings
{
get { return _supportedEncodings; }
}
/// <summary>
/// Returns the list of supported Media Types.
/// </summary>
public IList<string> SupportedMediaTypes
{
get { return _supportedMediaTypes; }
}
/// <summary>
/// Indicates the acceptable input XML depth.
/// </summary>
public int MaxDepth
{
get { return _readerQuotas.MaxDepth; }
set { _readerQuotas.MaxDepth = value; }
}
/// <summary>
/// The quotas include - DefaultMaxDepth, DefaultMaxStringContentLength, DefaultMaxArrayLength,
/// DefaultMaxBytesPerRead, DefaultMaxNameTableCharCount
/// </summary>
public XmlDictionaryReaderQuotas XmlDictionaryReaderQuotas
{
get { return _readerQuotas; }
}
/// <summary>
/// Reads the input XML.
/// </summary>
/// <param name="context">The input formatter context which contains the body to be read.</param>
/// <returns>Task which reads the input.</returns>
public async Task ReadAsync(InputFormatterContext context)
{
var request = context.HttpContext.Request;
if (request.ContentLength == 0)
{
context.Model = GetDefaultValueForType(context.Metadata.ModelType);
return;
}
context.Model = await ReadInternal(context);
}
/// <summary>
/// Called during deserialization to get the <see cref="XmlReader"/>.
/// </summary>
/// <param name="readStream">The <see cref="Stream"/> from which to read.</param>
/// <returns>The <see cref="XmlReader"/> used during deserialization.</returns>
protected virtual XmlReader CreateXmlReader([NotNull] Stream readStream)
{
return XmlDictionaryReader.CreateTextReader(
readStream, _readerQuotas);
}
/// <summary>
/// Called during deserialization to get the <see cref="XmlSerializer"/>.
/// </summary>
/// <returns>The <see cref="XmlSerializer"/> used during serialization and deserialization.</returns>
protected virtual XmlSerializer CreateXmlSerializer(Type type)
{
return new XmlSerializer(type);
}
private object GetDefaultValueForType(Type modelType)
{
if (modelType.GetTypeInfo().IsValueType)
{
return Activator.CreateInstance(modelType);
}
return null;
}
private Task<object> ReadInternal(InputFormatterContext context)
{
var type = context.Metadata.ModelType;
var request = context.HttpContext.Request;
using (var xmlReader = CreateXmlReader(new DelegatingStream(request.Body)))
{
var xmlSerializer = CreateXmlSerializer(type);
return Task.FromResult(xmlSerializer.Deserialize(xmlReader));
}
}
}
}

View File

@ -40,12 +40,16 @@
<Compile Include="Binders\MutableObjectModelBinder.cs" />
<Compile Include="Binders\TypeConverterModelBinder.cs" />
<Compile Include="Binders\TypeMatchModelBinder.cs" />
<Compile Include="Formatters\XmlDataContractSerializerInputFormatter.cs" />
<Compile Include="Formatters\DelegatingStream.cs" />
<Compile Include="Formatters\FormattingUtilities.cs" />
<Compile Include="Formatters\IInputFormatter.cs" />
<Compile Include="Formatters\IInputFormatterProvider.cs" />
<Compile Include="Formatters\InputFormatterContext.cs" />
<Compile Include="Formatters\InputFormatterProviderContext.cs" />
<Compile Include="Formatters\JsonInputFormatter.cs" />
<Compile Include="Formatters\TempInputFormatterProvider.cs" />
<Compile Include="Formatters\XmlSerializerInputFormatter.cs" />
<Compile Include="Internal\CollectionExtensions.cs" />
<Compile Include="Internal\CollectionModelBinderUtil.cs" />
<Compile Include="Internal\ContentTypeHeaderValue.cs" />

View File

@ -13,6 +13,7 @@
"frameworks": {
"net45": {
"dependencies": {
"System.Xml": "",
"System.ComponentModel.DataAnnotations": "",
"System.Runtime.Serialization": ""
}
@ -40,10 +41,13 @@
"System.Runtime.Extensions": "4.0.10.0",
"System.Runtime.InteropServices": "4.0.20.0",
"System.Runtime.Serialization.Primitives": "4.0.0.0",
"System.Runtime.Serialization.Xml": "4.0.0.0",
"System.Text.Encoding": "4.0.20.0",
"System.Text.Encoding.Extensions": "4.0.10.0",
"System.Threading": "4.0.0.0",
"System.Threading.Tasks": "4.0.10.0"
"System.Threading.Tasks": "4.0.10.0",
"System.Xml.ReaderWriter": "4.0.0.0",
"System.Xml.XmlSerializer": "4.0.0.0"
}
}
}

View File

@ -62,6 +62,8 @@ namespace Microsoft.AspNet.Mvc
yield return describe.Scoped<IActionBindingContextProvider, DefaultActionBindingContextProvider>();
yield return describe.Transient<IInputFormatter, JsonInputFormatter>();
yield return describe.Transient<IInputFormatter, XmlSerializerInputFormatter>();
yield return describe.Transient<IInputFormatter, XmlDataContractSerializerInputFormatter>();
yield return describe.Transient<IInputFormatterProvider, TempInputFormatterProvider>();
yield return describe.Transient<IModelBinderProvider, DefaultModelBindersProvider>();

View File

@ -0,0 +1,43 @@
// 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 Microsoft.AspNet.Builder;
using Microsoft.AspNet.TestHost;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class InputFormatterTests
{
private readonly IServiceProvider _services;
private readonly Action<IBuilder> _app = new FormatterWebSite.Startup().Configure;
public InputFormatterTests()
{
_services = TestHelper.CreateServices("FormatterWebSite");
}
[Fact]
public async Task CheckIfXmlInputFormatterIsBeingCalled()
{
// Arrange
var server = TestServer.Create(_services, _app);
var client = server.Handler;
var sampleInputInt = 10;
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>" + sampleInputInt.ToString() + "</SampleInt></DummyClass>";
// Act
var response = await client.PostAsync("http://localhost/Home/Index", input, "application/xml");
//Assert
Assert.Equal(200, response.StatusCode);
Assert.Equal(sampleInputInt.ToString(), await response.ReadBodyAsStringAsync());
}
// TODO: By default XmlSerializerInputFormatter is called because of the order in which
// the formatters are registered. Add a test to call into DataContractSerializerInputFormatter.
}
}

View File

@ -36,6 +36,7 @@
<Compile Include="CompositeViewEngineTests.cs" />
<Compile Include="DependencyResolverTests.cs" />
<Compile Include="InlineConstraintTests.cs" />
<Compile Include="InputFormatterTests.cs" />
<Compile Include="RoutingTests.cs" />
<Compile Include="TestAssemblyProvider.cs" />
<Compile Include="TestConfigurationProvider.cs" />

View File

@ -6,6 +6,7 @@
"ActivatorWebSite": "",
"BasicWebSite": "",
"CompositeViewEngine": "",
"FormatterWebSite": "",
"InlineConstraintsWebSite": "",
"Microsoft.AspNet.TestHost": "1.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "",

View File

@ -0,0 +1,41 @@
// 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.
#if NET45
using System.IO;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding.Test
{
public class DelegatingStreamTests
{
[Fact]
public void InnerStreamIsOpenOnClose()
{
// Arrange
var innerStream = new MemoryStream();
var delegatingStream = new DelegatingStream(innerStream);
// Act
delegatingStream.Close();
// Assert
Assert.True(innerStream.CanRead);
}
[Fact]
public void InnerStreamIsOpenOnDispose()
{
// Arrange
var innerStream = new MemoryStream();
var delegatingStream = new DelegatingStream(innerStream);
// Act
delegatingStream.Dispose();
// Assert
Assert.True(innerStream.CanRead);
}
}
}
#endif

View File

@ -0,0 +1,313 @@
// 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.
#if NET45
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.AspNet.Http;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class DataContractSerializerInputFormatterTests
{
[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;
public DateTime SampleDate { get; set; }
}
[DataContract(Name = "TestLevelTwo", Namespace = "")]
public class TestLevelTwo
{
[DataMember]
public string SampleString { get; set; }
[DataMember]
public TestLevelOne TestOne { get; set; }
}
[Fact]
public void XmlDataContractSerializerFormatterHasProperSuppportedMediaTypes()
{
// Arrange & Act
var formatter = new XmlDataContractSerializerInputFormatter();
// Assert
Assert.True(formatter.SupportedMediaTypes.Contains("application/xml"));
Assert.True(formatter.SupportedMediaTypes.Contains("text/xml"));
}
[Fact]
public void XmlDataContractSerializerFormatterHasProperSuppportedEncodings()
{
// Arrange & Act
var formatter = new XmlDataContractSerializerInputFormatter();
// Assert
Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-8"));
Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-16"));
}
[Fact]
public async Task XmlDataContractSerializerFormatterReadsSimpleTypes()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString></TestLevelOne>";
var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelOne>(context.Model);
var model = context.Model as TestLevelOne;
Assert.Equal(expectedInt, model.SampleInt);
Assert.Equal(expectedString, model.sampleString);
}
[Fact]
public async Task XmlDataContractSerializerFormatterReadsComplexTypes()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var expectedLevelTwoString = "102";
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>" + expectedLevelTwoString + "</SampleString>" +
"<TestOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString></TestOne></TestLevelTwo>";
var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelTwo>(context.Model);
var model = context.Model as TestLevelTwo;
Assert.Equal(expectedLevelTwoString, model.SampleString);
Assert.Equal(expectedInt, model.TestOne.SampleInt);
Assert.Equal(expectedString, model.TestOne.sampleString);
}
[Fact]
public async Task XmlDataContractSerializerFormatterReadsWhenMaxDepthIsModified()
{
// Arrange
var expectedInt = 10;
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>" + expectedInt + "</SampleInt></DummyClass>";
var formatter = new XmlDataContractSerializerInputFormatter();
formatter.MaxDepth = 10;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<DummyClass>(context.Model);
var model = context.Model as DummyClass;
Assert.Equal(expectedInt, model.SampleInt);
}
[Fact]
public async Task XmlDataContractSerializerFormatterThrowsOnExceededMaxDepth()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>test</SampleString>" +
"<TestOne><SampleInt>10</SampleInt>" +
"<sampleString>test</sampleString></TestOne></TestLevelTwo>";
var formatter = new XmlDataContractSerializerInputFormatter();
formatter.MaxDepth = 1;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act & Assert
await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context));
}
[Fact]
public async Task XmlDataContractSerializerFormatterThrowsWhenReaderQuotasAreChanged()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>test</SampleString>" +
"<TestOne><SampleInt>10</SampleInt>" +
"<sampleString>test</sampleString></TestOne></TestLevelTwo>";
var formatter = new XmlDataContractSerializerInputFormatter();
formatter.XmlDictionaryReaderQuotas.MaxStringContentLength = 2;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act & Assert
await Assert.ThrowsAsync(typeof(SerializationException), async () => await formatter.ReadAsync(context));
}
[Fact]
public void XmlDataContractSerializerFormatterThrowsWhenMaxDepthIsBelowOne()
{
// Arrange
var formatter = new XmlDataContractSerializerInputFormatter();
// Act & Assert
Assert.Throws(typeof(ArgumentException), () => formatter.MaxDepth = 0);
}
[Fact]
public async Task VerifyStreamIsOpenAfterRead()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>10</SampleInt></DummyClass>";
var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.True(context.HttpContext.Request.Body.CanRead);
}
[Fact]
public async Task XmlDataContractSerializerFormatterThrowsOnInvalidCharacters()
{
// Arrange
var inpStart = Encodings.UTF16EncodingLittleEndian.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>");
byte[] inp = { 192, 193 };
var inpEnd = Encodings.UTF16EncodingLittleEndian.GetBytes("</SampleInt></DummyClass>");
var contentBytes = new byte[inpStart.Length + inp.Length + inpEnd.Length];
Buffer.BlockCopy(inpStart, 0, contentBytes, 0, inpStart.Length);
Buffer.BlockCopy(inp, 0, contentBytes, inpStart.Length, inp.Length);
Buffer.BlockCopy(inpEnd, 0, contentBytes, inpStart.Length + inp.Length, inpEnd.Length);
var formatter = new XmlDataContractSerializerInputFormatter();
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await Assert.ThrowsAsync(typeof(XmlException), async () => await formatter.ReadAsync(context));
}
[Fact]
public async Task XmlDataContractSerializerFormatterIgnoresBOMCharacters()
{
// Arrange
var sampleString = "Test";
var sampleStringBytes = Encoding.UTF8.GetBytes(sampleString);
var inputStart = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Environment.NewLine +
"<TestLevelTwo><SampleString>" + sampleString);
byte[] bom = { 0xef, 0xbb, 0xbf };
var inputEnd = Encoding.UTF8.GetBytes("</SampleString></TestLevelTwo>");
var expectedBytes = new byte[sampleString.Length + bom.Length];
var contentBytes = new byte[inputStart.Length + bom.Length + inputEnd.Length];
Buffer.BlockCopy(inputStart, 0, contentBytes, 0, inputStart.Length);
Buffer.BlockCopy(bom, 0, contentBytes, inputStart.Length, bom.Length);
Buffer.BlockCopy(inputEnd, 0, contentBytes, inputStart.Length + bom.Length, inputEnd.Length);
var formatter = new XmlDataContractSerializerInputFormatter();
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
var model = context.Model as TestLevelTwo;
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(model.SampleString));
}
[Fact]
public async Task XmlDataContractSerializerAcceptsUTF16Characters()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" +
"<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString></TestLevelOne>";
var formatter = new XmlDataContractSerializerInputFormatter();
var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelOne>(context.Model);
var model = context.Model as TestLevelOne;
Assert.Equal(expectedInt, model.SampleInt);
Assert.Equal(expectedString, model.sampleString);
}
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
{
var httpContext = GetHttpContext(contentBytes);
var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
return new InputFormatterContext(httpContext, metadata, modelState);
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/xml")
{
var request = new Mock<HttpRequest>();
var headers = new Mock<IHeaderDictionary>();
headers.SetupGet(h => h["Content-Type"]).Returns(contentType);
request.SetupGet(r => r.Headers).Returns(headers.Object);
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Request).Returns(request.Object);
return httpContext.Object;
}
}
}
#endif

View File

@ -0,0 +1,317 @@
// 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.
#if NET45
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.AspNet.Http;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
public class XmlSerializerInputFormatterTests
{
public class DummyClass
{
public int SampleInt { get; set; }
}
public class TestLevelOne
{
public int SampleInt { get; set; }
public string sampleString;
public DateTime SampleDate { get; set; }
}
public class TestLevelTwo
{
public string SampleString { get; set; }
public TestLevelOne TestOne { get; set; }
}
[Fact]
public void XmlSerializerFormatterHasProperSuppportedMediaTypes()
{
// Arrange & Act
var formatter = new XmlSerializerInputFormatter();
// Assert
Assert.True(formatter.SupportedMediaTypes.Contains("application/xml"));
Assert.True(formatter.SupportedMediaTypes.Contains("text/xml"));
}
[Fact]
public void XmlSerializerFormatterHasProperSuppportedEncodings()
{
// Arrange & Act
var formatter = new XmlSerializerInputFormatter();
// Assert
Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-8"));
Assert.True(formatter.SupportedEncodings.Any(i => i.WebName == "utf-16"));
}
[Fact]
public async Task XmlSerializerFormatterReadsSimpleTypes()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var expectedDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc);
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString>" +
"<SampleDate>" + expectedDateTime + "</SampleDate></TestLevelOne>";
var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelOne>(context.Model);
var model = context.Model as TestLevelOne;
Assert.Equal(expectedInt, model.SampleInt);
Assert.Equal(expectedString, model.sampleString);
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.SampleDate);
}
[Fact]
public async Task XmlSerializerFormatterReadsComplexTypes()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var expectedDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc);
var expectedLevelTwoString = "102";
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>" + expectedLevelTwoString + "</SampleString>" +
"<TestOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString>" +
"<SampleDate>" + expectedDateTime + "</SampleDate></TestOne></TestLevelTwo>";
var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelTwo>(context.Model);
var model = context.Model as TestLevelTwo;
Assert.Equal(expectedLevelTwoString, model.SampleString);
Assert.Equal(expectedInt, model.TestOne.SampleInt);
Assert.Equal(expectedString, model.TestOne.sampleString);
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.TestOne.SampleDate);
}
[Fact]
public async Task XmlSerializerFormatterReadsWhenMaxDepthIsModified()
{
// Arrange
var expectedInt = 10;
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>" + expectedInt + "</SampleInt></DummyClass>";
var formatter = new XmlSerializerInputFormatter();
formatter.MaxDepth = 10;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<DummyClass>(context.Model);
var model = context.Model as DummyClass;
Assert.Equal(expectedInt, model.SampleInt);
}
[Fact]
public async Task XmlSerializerFormatterThrowsOnExceededMaxDepth()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>test</SampleString>" +
"<TestOne><SampleInt>10</SampleInt>" +
"<sampleString>test</sampleString>" +
"<SampleDate>" + XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc)
+ "</SampleDate></TestOne></TestLevelTwo>";
var formatter = new XmlSerializerInputFormatter();
formatter.MaxDepth = 1;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act & Assert
await Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await formatter.ReadAsync(context));
}
[Fact]
public async Task XmlSerializerFormatterThrowsWhenReaderQuotasAreChanged()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<TestLevelTwo><SampleString>test</SampleString>" +
"<TestOne><SampleInt>10</SampleInt>" +
"<sampleString>test</sampleString>" +
"<SampleDate>" + XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc)
+ "</SampleDate></TestOne></TestLevelTwo>";
var formatter = new XmlSerializerInputFormatter();
formatter.XmlDictionaryReaderQuotas.MaxStringContentLength = 10;
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act & Assert
await Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await formatter.ReadAsync(context));
}
[Fact]
public void XmlSerializerSerializerThrowsWhenMaxDepthIsBelowOne()
{
// Arrange
var formatter = new XmlSerializerInputFormatter();
// Act & Assert
Assert.Throws(typeof(ArgumentException), () => formatter.MaxDepth = 0);
}
[Fact]
public async Task VerifyStreamIsOpenAfterRead()
{
// Arrange
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>10</SampleInt></DummyClass>";
var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encoding.UTF8.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(DummyClass));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.True(context.HttpContext.Request.Body.CanRead);
}
[Fact]
public async Task XmlSerializerFormatterThrowsOnInvalidCharacters()
{
// Arrange
var inpStart = Encodings.UTF16EncodingLittleEndian.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<DummyClass><SampleInt>");
byte[] inp = { 192, 193 };
var inpEnd = Encodings.UTF16EncodingLittleEndian.GetBytes("</SampleInt></DummyClass>");
var contentBytes = new byte[inpStart.Length + inp.Length + inpEnd.Length];
Buffer.BlockCopy(inpStart, 0, contentBytes, 0, inpStart.Length);
Buffer.BlockCopy(inp, 0, contentBytes, inpStart.Length, inp.Length);
Buffer.BlockCopy(inpEnd, 0, contentBytes, inpStart.Length + inp.Length, inpEnd.Length);
var formatter = new XmlSerializerInputFormatter();
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await Assert.ThrowsAsync(typeof(XmlException), async () => await formatter.ReadAsync(context));
}
[Fact]
public async Task XmlSerializerFormatterIgnoresBOMCharacters()
{
// Arrange
var sampleString = "Test";
var sampleStringBytes = Encoding.UTF8.GetBytes(sampleString);
var inputStart = Encoding.UTF8.GetBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + Environment.NewLine +
"<TestLevelTwo><SampleString>" + sampleString);
byte[] bom = { 0xef, 0xbb, 0xbf };
var inputEnd = Encoding.UTF8.GetBytes("</SampleString></TestLevelTwo>");
var expectedBytes = new byte[sampleString.Length + bom.Length];
var contentBytes = new byte[inputStart.Length + bom.Length + inputEnd.Length];
Buffer.BlockCopy(inputStart, 0, contentBytes, 0, inputStart.Length);
Buffer.BlockCopy(bom, 0, contentBytes, inputStart.Length, bom.Length);
Buffer.BlockCopy(inputEnd, 0, contentBytes, inputStart.Length + bom.Length, inputEnd.Length);
var formatter = new XmlSerializerInputFormatter();
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelTwo));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
var model = context.Model as TestLevelTwo;
Buffer.BlockCopy(sampleStringBytes, 0, expectedBytes, 0, sampleStringBytes.Length);
Buffer.BlockCopy(bom, 0, expectedBytes, sampleStringBytes.Length, bom.Length);
Assert.Equal(expectedBytes, Encoding.UTF8.GetBytes(model.SampleString));
}
[Fact]
public async Task XmlSerializerFormatterAcceptsUTF16Characters()
{
// Arrange
var expectedInt = 10;
var expectedString = "TestString";
var expectedDateTime = XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc);
var input = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>" +
"<TestLevelOne><SampleInt>" + expectedInt + "</SampleInt>" +
"<sampleString>" + expectedString + "</sampleString>" +
"<SampleDate>" + expectedDateTime + "</SampleDate></TestLevelOne>";
var formatter = new XmlSerializerInputFormatter();
var contentBytes = Encodings.UTF16EncodingLittleEndian.GetBytes(input);
var context = GetInputFormatterContext(contentBytes, typeof(TestLevelOne));
// Act
await formatter.ReadAsync(context);
// Assert
Assert.NotNull(context.Model);
Assert.IsType<TestLevelOne>(context.Model);
var model = context.Model as TestLevelOne;
Assert.Equal(expectedInt, model.SampleInt);
Assert.Equal(expectedString, model.sampleString);
Assert.Equal(XmlConvert.ToDateTime(expectedDateTime, XmlDateTimeSerializationMode.Utc), model.SampleDate);
}
private InputFormatterContext GetInputFormatterContext(byte[] contentBytes, Type modelType)
{
var httpContext = GetHttpContext(contentBytes);
var modelState = new ModelStateDictionary();
var metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, modelType);
return new InputFormatterContext(httpContext, metadata, modelState);
}
private static HttpContext GetHttpContext(byte[] contentBytes,
string contentType = "application/xml")
{
var request = new Mock<HttpRequest>();
var headers = new Mock<IHeaderDictionary>();
headers.SetupGet(h => h["Content-Type"]).Returns(contentType);
request.SetupGet(r => r.Headers).Returns(headers.Object);
request.SetupGet(f => f.Body).Returns(new MemoryStream(contentBytes));
var httpContext = new Mock<HttpContext>();
httpContext.SetupGet(c => c.Request).Returns(request.Object);
return httpContext.Object;
}
}
}
#endif

View File

@ -32,7 +32,10 @@
<Compile Include="Binders\ModelBindingContextTest.cs" />
<Compile Include="Binders\MutableObjectModelBinderTest.cs" />
<Compile Include="Binders\TypeConverterModelBinderTest.cs" />
<Compile Include="Formatters\XmlDataContractSerializerInputFormatterTests.cs" />
<Compile Include="Formatters\DelegatingStreamTests.cs" />
<Compile Include="Formatters\JsonInputFormatterTest.cs" />
<Compile Include="Formatters\XmlSerializerInputFormatterTests.cs" />
<Compile Include="Internal\TypeExtensionTests.cs" />
<Compile Include="Metadata\AssociatedMetadataProviderTest.cs" />
<Compile Include="Metadata\CachedDataAnnotationsMetadataAttributesTest.cs" />

View File

@ -10,6 +10,7 @@
"Microsoft.AspNet.Testing": "1.0.0-*",
"Microsoft.DataAnnotations" : "1.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Moq": "4.2.1312.1622",
"Newtonsoft.Json": "5.0.8",
"Xunit.KRunner": "1.0.0-*"
},
@ -17,9 +18,8 @@
"test": "Xunit.KRunner"
},
"frameworks": {
"net45": {
dependencies: {
"Moq": "4.2.1312.1622",
"net45": {
"dependencies": {
"System.ComponentModel.DataAnnotations": "",
"System.Reflection": "",
"System.Runtime": "",
@ -27,7 +27,7 @@
}
},
"k10" : {
dependencies: {
"dependencies": {
"System.Collections": "4.0.10.0",
"System.ComponentModel": "4.0.0.0",
"System.Globalization": "4.0.10.0",

View File

@ -0,0 +1,16 @@
// 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.Controllers
{
public class HomeController : Controller
{
[HttpPost]
public IActionResult Index([FromBody]DummyClass dummyObject)
{
return Content(dummyObject.SampleInt.ToString());
}
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>62735776-46ff-4170-9392-02e128a69b89</ProjectGuid>
<OutputType>Web</OutputType>
</PropertyGroup>
<PropertyGroup Condition="$(OutputType) == 'Console'">
<DebuggerFlavor>ConsoleDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="$(OutputType) == 'Web'">
<DebuggerFlavor>WebDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" Label="Configuration">
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DevelopmentServerPort>38820</DevelopmentServerPort>
</PropertyGroup>
<ItemGroup>
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Models\DummyClass.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="project.json" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,10 @@
// 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.
namespace FormatterWebSite
{
public class DummyClass
{
public int SampleInt { get; set; }
}
}

View File

@ -0,0 +1,32 @@
// 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.Builder;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;
namespace FormatterWebSite
{
public class Startup
{
public void Configure(IBuilder app)
{
var configuration = app.GetTestConfiguration();
// Set up application services
app.UseServices(services =>
{
// Add MVC services to the services container
services.AddMvc(configuration);
});
// Add MVC to the request pipeline
app.UseMvc(routes =>
{
routes.MapRoute("ActionAsMethod", "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" });
});
}
}
}

View File

@ -0,0 +1,10 @@
{
"dependencies": {
"Microsoft.AspNet.Mvc": "",
"Microsoft.AspNet.Mvc.TestConfiguration": ""
},
"configurations": {
"net45": { },
"k10": { }
}
}