added InputFormatter base type
This commit is contained in:
parent
e1e43e1e8c
commit
13e1c9d5e1
|
|
@ -0,0 +1,105 @@
|
||||||
|
// 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.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc.Core;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an object from the request body.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class InputFormatter : IInputFormatter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the mutable collection of character encodings supported by
|
||||||
|
/// this <see cref="InputFormatter"/>. The encodings are
|
||||||
|
/// used when reading the data.
|
||||||
|
/// </summary>
|
||||||
|
public IList<Encoding> SupportedEncodings { get; } = new List<Encoding>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
|
||||||
|
/// this <see cref="InputFormatter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; } = new List<MediaTypeHeaderValue>();
|
||||||
|
|
||||||
|
protected object GetDefaultValueForType(Type modelType)
|
||||||
|
{
|
||||||
|
if (modelType.GetTypeInfo().IsValueType)
|
||||||
|
{
|
||||||
|
return Activator.CreateInstance(modelType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual bool CanRead(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
||||||
|
MediaTypeHeaderValue requestContentType;
|
||||||
|
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SupportedMediaTypes
|
||||||
|
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual async Task<object> ReadAsync(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
|
if (request.ContentLength == 0)
|
||||||
|
{
|
||||||
|
return GetDefaultValueForType(context.ModelType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await ReadRequestBodyAsync(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the request body.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="InputFormatterContext"/> associated with the call.</param>
|
||||||
|
/// <returns>A task which can read the request body.</returns>
|
||||||
|
public abstract Task<object> ReadRequestBodyAsync(InputFormatterContext context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns encoding based on content type charset parameter.
|
||||||
|
/// </summary>
|
||||||
|
protected Encoding SelectCharacterEncoding(MediaTypeHeaderValue contentType)
|
||||||
|
{
|
||||||
|
if (contentType != null)
|
||||||
|
{
|
||||||
|
var charset = contentType.Charset;
|
||||||
|
if (!string.IsNullOrWhiteSpace(contentType.Charset))
|
||||||
|
{
|
||||||
|
foreach (var supportedEncoding in SupportedEncodings)
|
||||||
|
{
|
||||||
|
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.FormatInputFormatterNoEncoding(GetType().FullName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,29 +2,24 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Mvc.Core;
|
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
public class JsonInputFormatter : IInputFormatter
|
public class JsonInputFormatter : InputFormatter
|
||||||
{
|
{
|
||||||
private const int DefaultMaxDepth = 32;
|
private const int DefaultMaxDepth = 32;
|
||||||
private JsonSerializerSettings _jsonSerializerSettings;
|
private JsonSerializerSettings _jsonSerializerSettings;
|
||||||
|
|
||||||
public JsonInputFormatter()
|
public JsonInputFormatter()
|
||||||
{
|
{
|
||||||
SupportedEncodings = new List<Encoding>();
|
|
||||||
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
||||||
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
||||||
SupportedMediaTypes = new List<MediaTypeHeaderValue>();
|
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json"));
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json"));
|
||||||
|
|
||||||
|
|
@ -42,12 +37,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; private set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<Encoding> SupportedEncodings { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
|
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -72,31 +61,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
public bool CaptureDeserilizationErrors { get; set; }
|
public bool CaptureDeserilizationErrors { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool CanRead(InputFormatterContext context)
|
public override Task<object> ReadRequestBodyAsync([NotNull] InputFormatterContext context)
|
||||||
{
|
|
||||||
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
|
||||||
MediaTypeHeaderValue requestContentType;
|
|
||||||
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SupportedMediaTypes
|
|
||||||
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task<object> ReadAsync([NotNull] InputFormatterContext context)
|
|
||||||
{
|
{
|
||||||
|
var type = context.ModelType;
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
|
||||||
{
|
|
||||||
var modelType = context.ModelType;
|
|
||||||
var model = modelType.GetTypeInfo().IsValueType ? Activator.CreateInstance(modelType) :
|
|
||||||
null;
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaTypeHeaderValue requestContentType = null;
|
MediaTypeHeaderValue requestContentType = null;
|
||||||
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
|
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
|
||||||
|
|
||||||
|
|
@ -104,38 +72,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Never non-null since SelectCharacterEncoding() throws in error / not found scenarios
|
// Never non-null since SelectCharacterEncoding() throws in error / not found scenarios
|
||||||
var effectiveEncoding = SelectCharacterEncoding(requestContentType);
|
var effectiveEncoding = SelectCharacterEncoding(requestContentType);
|
||||||
|
|
||||||
return await ReadInternal(context, effectiveEncoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called during deserialization to get the <see cref="JsonReader"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The <see cref="InputFormatterContext"/> for the read.</param>
|
|
||||||
/// <param name="readStream">The <see cref="Stream"/> from which to read.</param>
|
|
||||||
/// <param name="effectiveEncoding">The <see cref="Encoding"/> to use when reading.</param>
|
|
||||||
/// <returns>The <see cref="JsonReader"/> used during deserialization.</returns>
|
|
||||||
public virtual JsonReader CreateJsonReader([NotNull] InputFormatterContext context,
|
|
||||||
[NotNull] Stream readStream,
|
|
||||||
[NotNull] Encoding effectiveEncoding)
|
|
||||||
{
|
|
||||||
return new JsonTextReader(new StreamReader(readStream, effectiveEncoding));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called during deserialization to get the <see cref="JsonSerializer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
|
||||||
public virtual JsonSerializer CreateJsonSerializer()
|
|
||||||
{
|
|
||||||
return JsonSerializer.Create(SerializerSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<object> ReadInternal(InputFormatterContext context,
|
|
||||||
Encoding effectiveEncoding)
|
|
||||||
{
|
|
||||||
var type = context.ModelType;
|
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
|
||||||
|
|
||||||
using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding))
|
using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding))
|
||||||
{
|
{
|
||||||
jsonReader.CloseInput = false;
|
jsonReader.CloseInput = false;
|
||||||
|
|
@ -172,31 +108,27 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Encoding SelectCharacterEncoding(MediaTypeHeaderValue contentType)
|
/// <summary>
|
||||||
|
/// Called during deserialization to get the <see cref="JsonReader"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The <see cref="InputFormatterContext"/> for the read.</param>
|
||||||
|
/// <param name="readStream">The <see cref="Stream"/> from which to read.</param>
|
||||||
|
/// <param name="effectiveEncoding">The <see cref="Encoding"/> to use when reading.</param>
|
||||||
|
/// <returns>The <see cref="JsonReader"/> used during deserialization.</returns>
|
||||||
|
public virtual JsonReader CreateJsonReader([NotNull] InputFormatterContext context,
|
||||||
|
[NotNull] Stream readStream,
|
||||||
|
[NotNull] Encoding effectiveEncoding)
|
||||||
{
|
{
|
||||||
if (contentType != null)
|
return new JsonTextReader(new StreamReader(readStream, effectiveEncoding));
|
||||||
{
|
}
|
||||||
// Find encoding based on content type charset parameter
|
|
||||||
var charset = contentType.Charset;
|
|
||||||
if (!string.IsNullOrWhiteSpace(contentType.Charset))
|
|
||||||
{
|
|
||||||
foreach (var supportedEncoding in SupportedEncodings)
|
|
||||||
{
|
|
||||||
if (string.Equals(charset, supportedEncoding.WebName, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return supportedEncoding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SupportedEncodings.Count > 0)
|
/// <summary>
|
||||||
{
|
/// Called during deserialization to get the <see cref="JsonSerializer"/>.
|
||||||
return SupportedEncodings[0];
|
/// </summary>
|
||||||
}
|
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
||||||
|
public virtual JsonSerializer CreateJsonSerializer()
|
||||||
// No supported encoding was found so there is no way for us to start reading.
|
{
|
||||||
throw new InvalidOperationException(Resources.FormatInputFormatterNoEncoding(GetType().FullName));
|
return JsonSerializer.Create(SerializerSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// this <see cref="OutputFormatter"/>. The encodings are
|
/// this <see cref="OutputFormatter"/>. The encodings are
|
||||||
/// used when writing the data.
|
/// used when writing the data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<Encoding> SupportedEncodings { get; private set; }
|
public IList<Encoding> SupportedEncodings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
|
/// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Microsoft.AspNet.Mvc.Internal;
|
using Microsoft.AspNet.Mvc.Internal;
|
||||||
|
|
@ -19,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// This class handles deserialization of input XML data
|
/// This class handles deserialization of input XML data
|
||||||
/// to strongly-typed objects using <see cref="DataContractSerializer"/>.
|
/// to strongly-typed objects using <see cref="DataContractSerializer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class XmlDataContractSerializerInputFormatter : IInputFormatter
|
public class XmlDataContractSerializerInputFormatter : InputFormatter
|
||||||
{
|
{
|
||||||
private DataContractSerializerSettings _serializerSettings;
|
private DataContractSerializerSettings _serializerSettings;
|
||||||
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
|
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
|
||||||
|
|
@ -29,11 +26,9 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public XmlDataContractSerializerInputFormatter()
|
public XmlDataContractSerializerInputFormatter()
|
||||||
{
|
{
|
||||||
SupportedEncodings = new List<Encoding>();
|
|
||||||
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
||||||
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
||||||
|
|
||||||
SupportedMediaTypes = new List<MediaTypeHeaderValue>();
|
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
|
||||||
|
|
||||||
|
|
@ -49,12 +44,6 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<IWrapperProviderFactory> WrapperProviderFactories { get; }
|
public IList<IWrapperProviderFactory> WrapperProviderFactories { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<Encoding> SupportedEncodings { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the acceptable input XML depth.
|
/// Indicates the acceptable input XML depth.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -73,20 +62,6 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
get { return _readerQuotas; }
|
get { return _readerQuotas; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool CanRead(InputFormatterContext context)
|
|
||||||
{
|
|
||||||
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
|
||||||
MediaTypeHeaderValue requestContentType;
|
|
||||||
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SupportedMediaTypes
|
|
||||||
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="DataContractSerializerSettings"/> used to configure the
|
/// Gets or sets the <see cref="DataContractSerializerSettings"/> used to configure the
|
||||||
/// <see cref="DataContractSerializer"/>.
|
/// <see cref="DataContractSerializer"/>.
|
||||||
|
|
@ -110,15 +85,30 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
||||||
/// <returns>Task which reads the input.</returns>
|
/// <returns>Task which reads the input.</returns>
|
||||||
public async Task<object> ReadAsync(InputFormatterContext context)
|
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
|
||||||
{
|
|
||||||
return GetDefaultValueForType(context.ModelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await ReadInternalAsync(context);
|
using (var xmlReader = CreateXmlReader(new NonDisposableStream(request.Body)))
|
||||||
|
{
|
||||||
|
var type = GetSerializableType(context.ModelType);
|
||||||
|
|
||||||
|
var serializer = CreateSerializer(type);
|
||||||
|
|
||||||
|
var deserializedObject = serializer.ReadObject(xmlReader);
|
||||||
|
|
||||||
|
// Unwrap only if the original type was wrapped.
|
||||||
|
if (type != context.ModelType)
|
||||||
|
{
|
||||||
|
var unwrappable = deserializedObject as IUnwrappable;
|
||||||
|
if (unwrappable != null)
|
||||||
|
{
|
||||||
|
deserializedObject = unwrappable.Unwrap(declaredType: context.ModelType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(deserializedObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -154,41 +144,5 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
{
|
{
|
||||||
return new DataContractSerializer(type, _serializerSettings);
|
return new DataContractSerializer(type, _serializerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetDefaultValueForType(Type modelType)
|
|
||||||
{
|
|
||||||
if (modelType.GetTypeInfo().IsValueType)
|
|
||||||
{
|
|
||||||
return Activator.CreateInstance(modelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<object> ReadInternalAsync(InputFormatterContext context)
|
|
||||||
{
|
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
|
||||||
|
|
||||||
using (var xmlReader = CreateXmlReader(new NonDisposableStream(request.Body)))
|
|
||||||
{
|
|
||||||
var type = GetSerializableType(context.ModelType);
|
|
||||||
|
|
||||||
var serializer = CreateSerializer(type);
|
|
||||||
|
|
||||||
var deserializedObject = serializer.ReadObject(xmlReader);
|
|
||||||
|
|
||||||
// Unwrap only if the original type was wrapped.
|
|
||||||
if (type != context.ModelType)
|
|
||||||
{
|
|
||||||
var unwrappable = deserializedObject as IUnwrappable;
|
|
||||||
if (unwrappable != null)
|
|
||||||
{
|
|
||||||
deserializedObject = unwrappable.Unwrap(declaredType: context.ModelType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(deserializedObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
|
@ -19,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// This class handles deserialization of input XML data
|
/// This class handles deserialization of input XML data
|
||||||
/// to strongly-typed objects using <see cref="XmlSerializer"/>
|
/// to strongly-typed objects using <see cref="XmlSerializer"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class XmlSerializerInputFormatter : IInputFormatter
|
public class XmlSerializerInputFormatter : InputFormatter
|
||||||
{
|
{
|
||||||
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
|
private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
|
||||||
|
|
||||||
|
|
@ -28,11 +25,9 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public XmlSerializerInputFormatter()
|
public XmlSerializerInputFormatter()
|
||||||
{
|
{
|
||||||
SupportedEncodings = new List<Encoding>();
|
|
||||||
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
|
||||||
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
|
||||||
|
|
||||||
SupportedMediaTypes = new List<MediaTypeHeaderValue>();
|
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
|
||||||
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
|
||||||
|
|
||||||
|
|
@ -46,12 +41,6 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IList<IWrapperProviderFactory> WrapperProviderFactories { get; }
|
public IList<IWrapperProviderFactory> WrapperProviderFactories { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IList<Encoding> SupportedEncodings { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates the acceptable input XML depth.
|
/// Indicates the acceptable input XML depth.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -70,34 +59,35 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
get { return _readerQuotas; }
|
get { return _readerQuotas; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public bool CanRead(InputFormatterContext context)
|
|
||||||
{
|
|
||||||
var contentType = context.ActionContext.HttpContext.Request.ContentType;
|
|
||||||
MediaTypeHeaderValue requestContentType;
|
|
||||||
if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SupportedMediaTypes
|
|
||||||
.Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the input XML.
|
/// Reads the input XML.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
/// <param name="context">The input formatter context which contains the body to be read.</param>
|
||||||
/// <returns>Task which reads the input.</returns>
|
/// <returns>Task which reads the input.</returns>
|
||||||
public async Task<object> ReadAsync(InputFormatterContext context)
|
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
|
||||||
{
|
{
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
if (request.ContentLength == 0)
|
|
||||||
{
|
|
||||||
return GetDefaultValueForType(context.ModelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await ReadInternalAsync(context);
|
using (var xmlReader = CreateXmlReader(new NonDisposableStream(request.Body)))
|
||||||
|
{
|
||||||
|
var type = GetSerializableType(context.ModelType);
|
||||||
|
|
||||||
|
var serializer = CreateSerializer(type);
|
||||||
|
|
||||||
|
var deserializedObject = serializer.Deserialize(xmlReader);
|
||||||
|
|
||||||
|
// Unwrap only if the original type was wrapped.
|
||||||
|
if (type != context.ModelType)
|
||||||
|
{
|
||||||
|
var unwrappable = deserializedObject as IUnwrappable;
|
||||||
|
if (unwrappable != null)
|
||||||
|
{
|
||||||
|
deserializedObject = unwrappable.Unwrap(declaredType: context.ModelType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(deserializedObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -132,41 +122,5 @@ namespace Microsoft.AspNet.Mvc.Xml
|
||||||
{
|
{
|
||||||
return new XmlSerializer(type);
|
return new XmlSerializer(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetDefaultValueForType(Type modelType)
|
|
||||||
{
|
|
||||||
if (modelType.GetTypeInfo().IsValueType)
|
|
||||||
{
|
|
||||||
return Activator.CreateInstance(modelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<object> ReadInternalAsync(InputFormatterContext context)
|
|
||||||
{
|
|
||||||
var request = context.ActionContext.HttpContext.Request;
|
|
||||||
|
|
||||||
using (var xmlReader = CreateXmlReader(new NonDisposableStream(request.Body)))
|
|
||||||
{
|
|
||||||
var type = GetSerializableType(context.ModelType);
|
|
||||||
|
|
||||||
var serializer = CreateSerializer(type);
|
|
||||||
|
|
||||||
var deserializedObject = serializer.Deserialize(xmlReader);
|
|
||||||
|
|
||||||
// Unwrap only if the original type was wrapped.
|
|
||||||
if (type != context.ModelType)
|
|
||||||
{
|
|
||||||
var unwrappable = deserializedObject as IUnwrappable;
|
|
||||||
if (unwrappable != null)
|
|
||||||
{
|
|
||||||
deserializedObject = unwrappable.Unwrap(declaredType: context.ModelType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.FromResult(deserializedObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,5 +163,42 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
Assert.Equal(expectedSampleIntValue.ToString(), responseBody);
|
Assert.Equal(expectedSampleIntValue.ToString(), responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("utf-8")]
|
||||||
|
[InlineData("unicode")]
|
||||||
|
public async Task CustomFormatter_IsSelected_ForSupportedContentTypeAndEncoding(string encoding)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
var content = new StringContent("Test Content", Encoding.GetEncoding(encoding), "text/plain");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PostAsync("http://localhost/InputFormatter/ReturnInput/", content);
|
||||||
|
var responseBody = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal("Test Content", responseBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("image/png")]
|
||||||
|
[InlineData("image/jpeg")]
|
||||||
|
public async Task CustomFormatter_NotSelected_ForUnsupportedContentType(string contentType)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
var content = new StringContent("Test Content", Encoding.UTF8, contentType);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.PostAsync("http://localhost/InputFormatter/ReturnInput/", content);
|
||||||
|
var responseBody = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.AspNet.WebUtilities;
|
||||||
|
|
||||||
namespace FormatterWebSite.Controllers
|
namespace FormatterWebSite.Controllers
|
||||||
{
|
{
|
||||||
|
|
@ -35,5 +36,15 @@ namespace FormatterWebSite.Controllers
|
||||||
{
|
{
|
||||||
return dummy;
|
return dummy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult ReturnInput([FromBody] string test)
|
||||||
|
{
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
{
|
||||||
|
return new HttpStatusCodeResult(StatusCodes.Status400BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Content(test);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ namespace FormatterWebSite
|
||||||
options.ValidationExcludeFilters.Add(typeof(Supplier));
|
options.ValidationExcludeFilters.Add(typeof(Supplier));
|
||||||
|
|
||||||
options.AddXmlDataContractSerializerFormatter();
|
options.AddXmlDataContractSerializerFormatter();
|
||||||
|
options.InputFormatters.Add(new StringInputFormatter());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
namespace FormatterWebSite
|
||||||
|
{
|
||||||
|
public class StringInputFormatter : InputFormatter
|
||||||
|
{
|
||||||
|
public StringInputFormatter()
|
||||||
|
{
|
||||||
|
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/plain"));
|
||||||
|
|
||||||
|
SupportedEncodings.Add(Encoding.UTF8);
|
||||||
|
SupportedEncodings.Add(Encoding.Unicode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<object> ReadRequestBodyAsync(InputFormatterContext context)
|
||||||
|
{
|
||||||
|
var request = context.ActionContext.HttpContext.Request;
|
||||||
|
MediaTypeHeaderValue requestContentType = null;
|
||||||
|
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
|
||||||
|
var effectiveEncoding = SelectCharacterEncoding(requestContentType);
|
||||||
|
|
||||||
|
using (var reader = new StreamReader(request.Body, effectiveEncoding))
|
||||||
|
{
|
||||||
|
var stringContent = reader.ReadToEnd();
|
||||||
|
return Task.FromResult<object>(stringContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue