// 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.IO; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.Internal; using Microsoft.Framework.Internal; using Microsoft.Net.Http.Headers; using Newtonsoft.Json; namespace Microsoft.AspNet.Mvc { public class JsonInputFormatter : InputFormatter { private JsonSerializerSettings _serializerSettings; public JsonInputFormatter() : this(SerializerSettingsProvider.CreateSerializerSettings()) { } public JsonInputFormatter([NotNull] JsonSerializerSettings serializerSettings) { _serializerSettings = serializerSettings; SupportedEncodings.Add(UTF8EncodingWithoutBOM); SupportedEncodings.Add(UTF16EncodingLittleEndian); SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/json")); } /// /// Gets or sets the used to configure the . /// public JsonSerializerSettings SerializerSettings { get { return _serializerSettings; } [param: NotNull] set { _serializerSettings = value; } } /// public override Task ReadRequestBodyAsync([NotNull] InputFormatterContext context) { var type = context.ModelType; var request = context.HttpContext.Request; MediaTypeHeaderValue requestContentType = null; MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType); // Get the character encoding for the content // Never non-null since SelectCharacterEncoding() throws in error / not found scenarios var effectiveEncoding = SelectCharacterEncoding(requestContentType); using (var jsonReader = CreateJsonReader(context, request.Body, effectiveEncoding)) { jsonReader.CloseInput = false; var jsonSerializer = CreateJsonSerializer(); EventHandler errorHandler = null; errorHandler = (sender, e) => { var exception = e.ErrorContext.Error; context.ModelState.TryAddModelError(e.ErrorContext.Path, e.ErrorContext.Error); // Error must always be marked as handled // Failure to do so can cause the exception to be rethrown at every recursive level and // overflow the stack for x64 CLR processes e.ErrorContext.Handled = true; }; jsonSerializer.Error += errorHandler; try { return Task.FromResult(jsonSerializer.Deserialize(jsonReader, type)); } finally { // Clean up the error handler in case CreateJsonSerializer() reuses a serializer if (errorHandler != null) { jsonSerializer.Error -= errorHandler; } } } } /// /// Called during deserialization to get the . /// /// The for the read. /// The from which to read. /// The to use when reading. /// The used during deserialization. protected virtual JsonReader CreateJsonReader( [NotNull] InputFormatterContext context, [NotNull] Stream readStream, [NotNull] Encoding effectiveEncoding) { return new JsonTextReader(new StreamReader(readStream, effectiveEncoding)); } /// /// Called during deserialization to get the . /// /// The used during serialization and deserialization. protected virtual JsonSerializer CreateJsonSerializer() { return JsonSerializer.Create(SerializerSettings); } } }