aspnetcore/src/Microsoft.AspNet.Mvc.ModelB.../Formatters/XmlSerializerInputFormatter.cs

120 lines
4.3 KiB
C#

// 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;
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
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 XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas();
/// <summary>
/// Initializes a new instance of XmlSerializerInputFormatter.
/// </summary>
public XmlSerializerInputFormatter()
{
SupportedEncodings = new List<Encoding>();
SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM);
SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian);
SupportedMediaTypes = new List<MediaTypeHeaderValue>();
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml"));
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml"));
}
/// <inheritdoc />
public IList<MediaTypeHeaderValue> SupportedMediaTypes { get; private set; }
/// <inheritdoc />
public IList<Encoding> SupportedEncodings { get; private set; }
/// <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 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));
}
}
}
}