// Copyright (c) .NET Foundation. 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 { /// /// Reads an object from the request body. /// public abstract class InputFormatter : IInputFormatter { /// /// Returns UTF8 Encoding without BOM and throws on invalid bytes. /// protected static readonly Encoding UTF8EncodingWithoutBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); /// /// Returns UTF16 Encoding which uses littleEndian byte order with BOM and throws on invalid bytes. /// protected static readonly Encoding UTF16EncodingLittleEndian = new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true); /// /// Gets the mutable collection of character encodings supported by /// this . The encodings are /// used when reading the data. /// public IList SupportedEncodings { get; } = new List(); /// /// Gets the mutable collection of elements supported by /// this . /// public IList SupportedMediaTypes { get; } = new List(); protected object GetDefaultValueForType(Type modelType) { if (modelType.GetTypeInfo().IsValueType) { return Activator.CreateInstance(modelType); } return null; } /// public virtual bool CanRead(InputFormatterContext context) { if (!CanReadType(context.ModelType)) { return false; } var contentType = context.HttpContext.Request.ContentType; MediaTypeHeaderValue requestContentType; if (!MediaTypeHeaderValue.TryParse(contentType, out requestContentType)) { return false; } return SupportedMediaTypes .Any(supportedMediaType => supportedMediaType.IsSubsetOf(requestContentType)); } /// /// Returns a value indicating whether or not the given type can be read by this serializer. /// /// The type of object that will be read. /// true if the type can be read, otherwise false. protected virtual bool CanReadType(Type type) { return true; } /// public virtual async Task ReadAsync(InputFormatterContext context) { var request = context.HttpContext.Request; if (request.ContentLength == 0) { return GetDefaultValueForType(context.ModelType); } return await ReadRequestBodyAsync(context); } /// /// Reads the request body. /// /// The associated with the call. /// A task which can read the request body. public abstract Task ReadRequestBodyAsync(InputFormatterContext context); /// /// Returns encoding based on content type charset parameter. /// 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)); } } }