aspnetcore/src/Microsoft.AspNet.Mvc.Core/InputFormatter.cs

132 lines
4.8 KiB
C#

// 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
{
/// <summary>
/// Reads an object from the request body.
/// </summary>
public abstract class InputFormatter : IInputFormatter
{
/// <summary>
/// Returns UTF8 Encoding without BOM and throws on invalid bytes.
/// </summary>
protected static readonly Encoding UTF8EncodingWithoutBOM
= new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
/// <summary>
/// Returns UTF16 Encoding which uses littleEndian byte order with BOM and throws on invalid bytes.
/// </summary>
protected static readonly Encoding UTF16EncodingLittleEndian
= new UnicodeEncoding(bigEndian: false, byteOrderMark: true, throwOnInvalidBytes: true);
/// <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)
{
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));
}
/// <summary>
/// Returns a value indicating whether or not the given type can be read by this serializer.
/// </summary>
/// <param name="type">The type of object that will be read.</param>
/// <returns><c>true</c> if the type can be read, otherwise <c>false</c>.</returns>
protected virtual bool CanReadType(Type type)
{
return true;
}
/// <inheritdoc />
public virtual async Task<object> ReadAsync(InputFormatterContext context)
{
var request = context.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));
}
}
}