aspnetcore/src/Microsoft.AspNet.Mvc.Core/ActionResults/JsonResult.cs

163 lines
6.0 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// An action result which formats the given object as JSON.
/// </summary>
public class JsonResult : ActionResult
{
/// <summary>
/// The list of content-types used for formatting when <see cref="ContentTypes"/> is null or empty.
/// </summary>
public static readonly IReadOnlyList<MediaTypeHeaderValue> DefaultContentTypes = new MediaTypeHeaderValue[]
{
MediaTypeHeaderValue.Parse("application/json"),
MediaTypeHeaderValue.Parse("text/json"),
};
/// <summary>
/// Creates a new <see cref="JsonResult"/> with the given <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to format as JSON.</param>
public JsonResult(object value)
: this(value, formatter: null)
{
}
/// <summary>
/// Creates a new <see cref="JsonResult"/> with the given <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to format as JSON.</param>
/// <param name="serializerSettings">The <see cref="JsonSerializerSettings"/> to be used by
/// the formatter.</param>
public JsonResult(object value, [NotNull] JsonSerializerSettings serializerSettings)
: this(value, formatter: new JsonOutputFormatter(serializerSettings))
{
}
/// <summary>
/// Creates a new <see cref="JsonResult"/> with the given <paramref name="value"/>.
/// </summary>
/// <param name="value">The value to format as JSON.</param>
/// <param name="formatter">The formatter to use, or <c>null</c> to choose a formatter dynamically.</param>
public JsonResult(object value, IOutputFormatter formatter)
{
Value = value;
Formatter = formatter;
ContentTypes = new List<MediaTypeHeaderValue>();
}
/// <summary>
/// Gets or sets the list of supported Content-Types.
/// </summary>
public IList<MediaTypeHeaderValue> ContentTypes { get; set; }
/// <summary>
/// Gets or sets the formatter.
/// </summary>
public IOutputFormatter Formatter { get; set; }
/// <summary>
/// Gets or sets the HTTP status code.
/// </summary>
public int? StatusCode { get; set; }
/// <summary>
/// Gets or sets the value to be formatted.
/// </summary>
public object Value { get; set; }
/// <inheritdoc />
public override async Task ExecuteResultAsync([NotNull] ActionContext context)
{
var objectResult = new ObjectResult(Value);
// Set the content type explicitly to application/json and text/json.
// if the user has not already set it.
if (ContentTypes == null || ContentTypes.Count == 0)
{
foreach (var contentType in DefaultContentTypes)
{
objectResult.ContentTypes.Add(contentType);
}
}
else
{
objectResult.ContentTypes = ContentTypes;
}
var formatterContext = new OutputFormatterContext()
{
ActionContext = context,
DeclaredType = objectResult.DeclaredType,
Object = Value,
};
// JsonResult expects to always find a formatter, in contrast with ObjectResult, which might return
// a 406.
var formatter = SelectFormatter(objectResult, formatterContext);
Debug.Assert(formatter != null);
if (StatusCode != null)
{
context.HttpContext.Response.StatusCode = StatusCode.Value;
}
await formatter.WriteAsync(formatterContext);
}
private IOutputFormatter SelectFormatter(ObjectResult objectResult, OutputFormatterContext formatterContext)
{
if (Formatter == null)
{
// If no formatter was provided, then run Conneg with the formatters configured in options.
var formatters = formatterContext
.ActionContext
.HttpContext
.RequestServices
.GetRequiredService<IOptions<MvcOptions>>()
.Options
.OutputFormatters
.OfType<IJsonOutputFormatter>()
.ToArray();
var formatter = objectResult.SelectFormatter(formatterContext, formatters);
if (formatter == null)
{
// If the available user-configured formatters can't write this type, then fall back to the
// 'global' one.
formatter = formatterContext
.ActionContext
.HttpContext
.RequestServices
.GetRequiredService<JsonOutputFormatter>();
// Run SelectFormatter again to try to choose a content type that this formatter can do.
objectResult.SelectFormatter(formatterContext, new[] { formatter });
}
return formatter;
}
else
{
// Run SelectFormatter to try to choose a content type that this formatter can do.
objectResult.SelectFormatter(formatterContext, new[] { Formatter });
return Formatter;
}
}
}
}