Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,7 @@ public MvcOptions() { }
public bool RequireHttpsPermanent { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool RespectBrowserAcceptHeader { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool ReturnHttpNotAcceptable { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.Text.Json.Serialization.JsonSerializerOptions SerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public int? SslPort { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool SuppressAsyncSuffixInActionNames { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public bool SuppressInputFormatterBuffering { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
Expand Down Expand Up @@ -1855,6 +1856,21 @@ public StringOutputFormatter() { }
public override bool CanWriteResult(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterCanWriteContext context) { throw null; }
public override System.Threading.Tasks.Task WriteResponseBodyAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext context, System.Text.Encoding encoding) { throw null; }
}
public partial class SystemTextJsonInputFormatter : Microsoft.AspNetCore.Mvc.Formatters.TextInputFormatter, Microsoft.AspNetCore.Mvc.Formatters.IInputFormatterExceptionPolicy
{
public SystemTextJsonInputFormatter(Microsoft.AspNetCore.Mvc.MvcOptions options) { }
Microsoft.AspNetCore.Mvc.Formatters.InputFormatterExceptionPolicy Microsoft.AspNetCore.Mvc.Formatters.IInputFormatterExceptionPolicy.ExceptionPolicy { get { throw null; } }
public System.Text.Json.Serialization.JsonSerializerOptions SerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
[System.Diagnostics.DebuggerStepThroughAttribute]
public sealed override System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.Formatters.InputFormatterResult> ReadRequestBodyAsync(Microsoft.AspNetCore.Mvc.Formatters.InputFormatterContext context, System.Text.Encoding encoding) { throw null; }
}
public partial class SystemTextJsonOutputFormatter : Microsoft.AspNetCore.Mvc.Formatters.TextOutputFormatter
{
public SystemTextJsonOutputFormatter(Microsoft.AspNetCore.Mvc.MvcOptions options) { }
public System.Text.Json.Serialization.JsonSerializerOptions SerializerOptions { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
[System.Diagnostics.DebuggerStepThroughAttribute]
public sealed override System.Threading.Tasks.Task WriteResponseBodyAsync(Microsoft.AspNetCore.Mvc.Formatters.OutputFormatterWriteContext context, System.Text.Encoding selectedEncoding) { throw null; }
}
public abstract partial class TextInputFormatter : Microsoft.AspNetCore.Mvc.Formatters.InputFormatter
{
protected static readonly System.Text.Encoding UTF16EncodingLittleEndian;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@

using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
namespace Microsoft.AspNetCore.Mvc.Formatters
{
internal static class MediaTypeHeaderValues
{
public static readonly MediaTypeHeaderValue ApplicationJson
= MediaTypeHeaderValue.Parse("application/json").CopyAsReadOnly();

public static readonly MediaTypeHeaderValue TextJson
= MediaTypeHeaderValue.Parse("text/json").CopyAsReadOnly();

public static readonly MediaTypeHeaderValue ApplicationAnyJsonSyntax
= MediaTypeHeaderValue.Parse("application/*+json").CopyAsReadOnly();

public static readonly MediaTypeHeaderValue ApplicationXml
= MediaTypeHeaderValue.Parse("application/xml").CopyAsReadOnly();

Expand Down
102 changes: 102 additions & 0 deletions src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonInputFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters.Json;

namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// A <see cref="TextInputFormatter"/> for JSON content that uses <see cref="JsonSerializer"/>.
/// </summary>
public class SystemTextJsonInputFormatter : TextInputFormatter, IInputFormatterExceptionPolicy
{
/// <summary>
/// Initializes a new instance of <see cref="SystemTextJsonInputFormatter"/>.
/// </summary>
/// <param name="options">The <see cref="MvcOptions"/>.</param>
public SystemTextJsonInputFormatter(MvcOptions options)
{
SerializerOptions = options.SerializerOptions;

SupportedEncodings.Add(UTF8EncodingWithoutBOM);
SupportedEncodings.Add(UTF16EncodingLittleEndian);

SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson);
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson);
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}

/// <summary>
/// Gets the <see cref="JsonSerializerOptions"/> used to configure the <see cref="JsonSerializer"/>.
/// </summary>
/// <remarks>
/// A single instance of <see cref="SystemTextJsonInputFormatter"/> is used for all JSON formatting. Any
/// changes to the options will affect all input formatting.
/// </remarks>
public JsonSerializerOptions SerializerOptions { get; }

/// <inheritdoc />
InputFormatterExceptionPolicy IInputFormatterExceptionPolicy.ExceptionPolicy => InputFormatterExceptionPolicy.MalformedInputExceptions;

/// <inheritdoc />
public sealed override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context,
Encoding encoding)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

if (encoding == null)
{
throw new ArgumentNullException(nameof(encoding));
}

var httpContext = context.HttpContext;
var inputStream = GetInputStream(httpContext, encoding);

object model;
try
{
model = await JsonSerializer.ReadAsync(inputStream, context.ModelType, SerializerOptions);
}
finally
{
if (inputStream is TranscodingReadStream transcoding)
{
transcoding.Dispose();
}
}

if (model == null && !context.TreatEmptyInputAsDefaultValue)
{
// Some nonempty inputs might deserialize as null, for example whitespace,
// or the JSON-encoded value "null". The upstream BodyModelBinder needs to
// be notified that we don't regard this as a real input so it can register
// a model binding error.
return InputFormatterResult.NoValue();
}
else
{
return InputFormatterResult.Success(model);
}
}

private Stream GetInputStream(HttpContext httpContext, Encoding encoding)
{
if (encoding.CodePage == Encoding.UTF8.CodePage)
{
return httpContext.Request.Body;
}

return new TranscodingReadStream(httpContext.Request.Body, encoding);
}
}
}
86 changes: 86 additions & 0 deletions src/Mvc/Mvc.Core/src/Formatters/SystemTextJsonOutputFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters.Json;

namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// A <see cref="TextOutputFormatter"/> for JSON content that uses <see cref="JsonSerializer"/>.
/// </summary>
public class SystemTextJsonOutputFormatter : TextOutputFormatter
{

/// <summary>
/// Initializes a new <see cref="SystemTextJsonOutputFormatter"/> instance.
/// </summary>
/// <param name="options">The <see cref="MvcOptions"/>.</param>
public SystemTextJsonOutputFormatter(MvcOptions options)
{
SerializerOptions = options.SerializerOptions;

SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationJson);
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextJson);
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyJsonSyntax);
}

/// <summary>
/// Gets the <see cref="JsonSerializerOptions"/> used to configure the <see cref="JsonSerializer"/>.
/// </summary>
/// <remarks>
/// A single instance of <see cref="SystemTextJsonOutputFormatter"/> is used for all JSON formatting. Any
/// changes to the options will affect all output formatting.
/// </remarks>
public JsonSerializerOptions SerializerOptions { get; }

/// <inheritdoc />
public sealed override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}

if (selectedEncoding == null)
{
throw new ArgumentNullException(nameof(selectedEncoding));
}

var httpContext = context.HttpContext;

var writeStream = GetWriteStream(httpContext, selectedEncoding);
try
{
await JsonSerializer.WriteAsync(context.Object, context.ObjectType, writeStream, SerializerOptions);
await writeStream.FlushAsync();
}
finally
{
if (writeStream is TranscodingWriteStream transcoding)
{
transcoding.Dispose();
}
}
}

private Stream GetWriteStream(HttpContext httpContext, Encoding selectedEncoding)
{
if (selectedEncoding.CodePage == Encoding.UTF8.CodePage)
{
// JsonSerializer does not write a BOM. Therefore we do not have to handle it
// in any special way.
return httpContext.Response.Body;
}

return new TranscodingWriteStream(httpContext.Response.Body, selectedEncoding);
}
}
}
Loading