// 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 { /// /// This class handles deserialization of input XML data /// to strongly-typed objects using /// public class XmlSerializerInputFormatter : IInputFormatter { private readonly XmlDictionaryReaderQuotas _readerQuotas = FormattingUtilities.GetDefaultXmlReaderQuotas(); /// /// Initializes a new instance of XmlSerializerInputFormatter. /// public XmlSerializerInputFormatter() { SupportedEncodings = new List(); SupportedEncodings.Add(Encodings.UTF8EncodingWithoutBOM); SupportedEncodings.Add(Encodings.UTF16EncodingLittleEndian); SupportedMediaTypes = new List(); SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/xml")); SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/xml")); } /// public IList SupportedMediaTypes { get; private set; } /// public IList SupportedEncodings { get; private set; } /// /// Indicates the acceptable input XML depth. /// public int MaxDepth { get { return _readerQuotas.MaxDepth; } set { _readerQuotas.MaxDepth = value; } } /// /// The quotas include - DefaultMaxDepth, DefaultMaxStringContentLength, DefaultMaxArrayLength, /// DefaultMaxBytesPerRead, DefaultMaxNameTableCharCount /// public XmlDictionaryReaderQuotas XmlDictionaryReaderQuotas { get { return _readerQuotas; } } /// /// Reads the input XML. /// /// The input formatter context which contains the body to be read. /// Task which reads the input. 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); } /// /// Called during deserialization to get the . /// /// The from which to read. /// The used during deserialization. protected virtual XmlReader CreateXmlReader([NotNull] Stream readStream) { return XmlDictionaryReader.CreateTextReader( readStream, _readerQuotas); } /// /// Called during deserialization to get the . /// /// The used during deserialization. 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 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)); } } } }