1. Introducing XML Input Formatters.
2. Adding DelegatingStream class 3. Unit + Functional tests for formatters.
This commit is contained in:
parent
43d1253936
commit
cee73c0af3
13
Mvc.sln
13
Mvc.sln
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"ActivatorWebSite": "",
|
||||
"BasicWebSite": "",
|
||||
"CompositeViewEngine": "",
|
||||
"FormatterWebSite": "",
|
||||
"InlineConstraintsWebSite": "",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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" });
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": ""
|
||||
},
|
||||
"configurations": {
|
||||
"net45": { },
|
||||
"k10": { }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue