[Fixes #2715] Removed formatter dependency from JsonResult and JsonViewComponentResult
This commit is contained in:
parent
d2908e7b7b
commit
e2787b3b84
|
|
@ -1,13 +1,10 @@
|
|||
// 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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -18,13 +15,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </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[]
|
||||
private readonly JsonSerializerSettings _serializerSettings;
|
||||
|
||||
private static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("application/json")
|
||||
{
|
||||
MediaTypeHeaderValue.Parse("application/json"),
|
||||
MediaTypeHeaderValue.Parse("text/json"),
|
||||
Encoding = Encoding.UTF8
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -32,7 +27,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
/// <param name="value">The value to format as JSON.</param>
|
||||
public JsonResult(object value)
|
||||
: this(value, formatter: null)
|
||||
: this(value, serializerSettings: SerializerSettingsProvider.CreateSerializerSettings())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -43,32 +38,15 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// <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>();
|
||||
_serializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of supported Content-Types.
|
||||
/// Gets or sets the <see cref="MediaTypeHeaderValue"/> representing the Content-Type header of the response.
|
||||
/// </summary>
|
||||
public IList<MediaTypeHeaderValue> ContentTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatter.
|
||||
/// </summary>
|
||||
public IOutputFormatter Formatter { get; set; }
|
||||
public MediaTypeHeaderValue ContentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP status code.
|
||||
|
|
@ -81,80 +59,44 @@ namespace Microsoft.AspNet.Mvc
|
|||
public object Value { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task ExecuteResultAsync([NotNull] ActionContext context)
|
||||
public override Task ExecuteResultAsync([NotNull] ActionContext context)
|
||||
{
|
||||
var objectResult = new ObjectResult(Value);
|
||||
var response = context.HttpContext.Response;
|
||||
|
||||
// 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)
|
||||
var contentTypeHeader = ContentType;
|
||||
if (contentTypeHeader == null)
|
||||
{
|
||||
foreach (var contentType in DefaultContentTypes)
|
||||
{
|
||||
objectResult.ContentTypes.Add(contentType);
|
||||
}
|
||||
contentTypeHeader = DefaultContentType;
|
||||
}
|
||||
else
|
||||
{
|
||||
objectResult.ContentTypes = ContentTypes;
|
||||
if (contentTypeHeader.Encoding == null)
|
||||
{
|
||||
// 1. Do not modify the user supplied content type
|
||||
// 2. Parse here to handle parameters apart from charset
|
||||
contentTypeHeader = MediaTypeHeaderValue.Parse(contentTypeHeader.ToString());
|
||||
contentTypeHeader.Encoding = Encoding.UTF8;
|
||||
}
|
||||
}
|
||||
|
||||
var formatterContext = new OutputFormatterContext()
|
||||
{
|
||||
HttpContext = context.HttpContext,
|
||||
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);
|
||||
response.ContentType = contentTypeHeader.ToString();
|
||||
|
||||
if (StatusCode != null)
|
||||
{
|
||||
context.HttpContext.Response.StatusCode = StatusCode.Value;
|
||||
response.StatusCode = StatusCode.Value;
|
||||
}
|
||||
|
||||
await formatter.WriteAsync(formatterContext);
|
||||
}
|
||||
|
||||
private IOutputFormatter SelectFormatter(ObjectResult objectResult, OutputFormatterContext formatterContext)
|
||||
{
|
||||
if (Formatter == null)
|
||||
using (var writer = new HttpResponseStreamWriter(response.Body, contentTypeHeader.Encoding))
|
||||
{
|
||||
// If no formatter was provided, then run Conneg with the formatters configured in options.
|
||||
var formatters = formatterContext
|
||||
.HttpContext
|
||||
.RequestServices
|
||||
.GetRequiredService<IOptions<MvcOptions>>()
|
||||
.Options
|
||||
.OutputFormatters
|
||||
.OfType<JsonOutputFormatter>()
|
||||
.ToArray();
|
||||
|
||||
var formatter = objectResult.SelectFormatter(formatterContext, formatters);
|
||||
if (formatter == null)
|
||||
using (var jsonWriter = new JsonTextWriter(writer))
|
||||
{
|
||||
// If the available user-configured formatters can't write this type, then fall back to the
|
||||
// 'global' one.
|
||||
formatter = formatterContext
|
||||
.HttpContext
|
||||
.RequestServices
|
||||
.GetRequiredService<JsonOutputFormatter>();
|
||||
|
||||
// Run SelectFormatter again to try to choose a content type that this formatter can do.
|
||||
objectResult.SelectFormatter(formatterContext, new[] { formatter });
|
||||
jsonWriter.CloseOutput = false;
|
||||
var jsonSerializer = JsonSerializer.Create(_serializerSettings);
|
||||
jsonSerializer.Serialize(jsonWriter, Value);
|
||||
}
|
||||
}
|
||||
|
||||
return formatter;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Run SelectFormatter to try to choose a content type that this formatter can do.
|
||||
objectResult.SelectFormatter(formatterContext, new[] { Formatter });
|
||||
return Formatter;
|
||||
}
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -13,12 +13,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public class JsonViewComponentResult : IViewComponentResult
|
||||
{
|
||||
private readonly JsonSerializerSettings _serializerSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="JsonViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to format as JSON text.</param>
|
||||
public JsonViewComponentResult(object value)
|
||||
: this(value, formatter: null)
|
||||
: this(value, serializerSettings: SerializerSettingsProvider.CreateSerializerSettings())
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -29,19 +31,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// <param name="serializerSettings">The <see cref="JsonSerializerSettings"/> to be used by
|
||||
/// the formatter.</param>
|
||||
public JsonViewComponentResult(object value, [NotNull] JsonSerializerSettings serializerSettings)
|
||||
: this(value, new JsonOutputFormatter(serializerSettings))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="JsonViewComponentResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to format as JSON text.</param>
|
||||
/// <param name="formatter">The <see cref="JsonOutputFormatter"/> to use.</param>
|
||||
public JsonViewComponentResult(object value, JsonOutputFormatter formatter)
|
||||
{
|
||||
Value = value;
|
||||
Formatter = formatter;
|
||||
_serializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -49,19 +41,18 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public object Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatter.
|
||||
/// </summary>
|
||||
public JsonOutputFormatter Formatter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Renders JSON text to the output.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ViewComponentContext"/>.</param>
|
||||
public void Execute([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var formatter = Formatter ?? ResolveFormatter(context);
|
||||
formatter.WriteObject(context.Writer, Value);
|
||||
using (var jsonWriter = new JsonTextWriter(context.Writer))
|
||||
{
|
||||
jsonWriter.CloseOutput = false;
|
||||
var jsonSerializer = JsonSerializer.Create(_serializerSettings);
|
||||
jsonSerializer.Serialize(jsonWriter, Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -74,11 +65,5 @@ namespace Microsoft.AspNet.Mvc
|
|||
Execute(context);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
private static JsonOutputFormatter ResolveFormatter(ViewComponentContext context)
|
||||
{
|
||||
var services = context.ViewContext.HttpContext.RequestServices;
|
||||
return services.GetRequiredService<JsonOutputFormatter>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||
using Microsoft.Framework.Internal;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace System.Web.Http
|
||||
|
|
@ -257,9 +258,7 @@ namespace System.Web.Http
|
|||
[NonAction]
|
||||
public virtual JsonResult Json<T>([NotNull] T content, [NotNull] JsonSerializerSettings serializerSettings)
|
||||
{
|
||||
var formatter = new JsonOutputFormatter(serializerSettings);
|
||||
|
||||
return new JsonResult(content, formatter);
|
||||
return new JsonResult(content, serializerSettings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -276,12 +275,13 @@ namespace System.Web.Http
|
|||
[NotNull] JsonSerializerSettings serializerSettings,
|
||||
[NotNull] Encoding encoding)
|
||||
{
|
||||
var formatter = new JsonOutputFormatter(serializerSettings);
|
||||
var result = new JsonResult(content, serializerSettings);
|
||||
result.ContentType = new MediaTypeHeaderValue("application/json")
|
||||
{
|
||||
Encoding = encoding
|
||||
};
|
||||
|
||||
formatter.SupportedEncodings.Clear();
|
||||
formatter.SupportedEncodings.Add(encoding);
|
||||
|
||||
return new JsonResult(content, formatter);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1033,7 +1033,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void Controller_Json_WithParameterValueAndSerializerSettings_SetsRespectiveValues()
|
||||
public void Controller_Json_WithParameterValue_SetsRespectiveProperty()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new TestableController();
|
||||
|
|
@ -1046,8 +1046,6 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
// Assert
|
||||
Assert.IsType<JsonResult>(actualJsonResult);
|
||||
Assert.Same(data, actualJsonResult.Value);
|
||||
var jsonFormatter = actualJsonResult.Formatter as JsonOutputFormatter;
|
||||
Assert.Same(serializerSettings, jsonFormatter.SerializerSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -1094,8 +1092,6 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
// Assert
|
||||
Assert.IsType<JsonResult>(result);
|
||||
Assert.Same(input, result.Value);
|
||||
var jsonFormatter = result.Formatter as JsonOutputFormatter;
|
||||
Assert.Same(serializerSettings, jsonFormatter.SerializerSettings);
|
||||
mockHttpContext.Verify(
|
||||
x => x.Response.OnResponseCompleted(It.IsAny<Action<object>>(), It.IsAny<object>()),
|
||||
Times.Once());
|
||||
|
|
|
|||
|
|
@ -228,8 +228,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.NotNull(jsonResult.Value);
|
||||
Assert.Same(model, jsonResult.Value);
|
||||
Assert.IsType<MyModel>(jsonResult.Value);
|
||||
var jsonFormatter = jsonResult.Formatter as JsonOutputFormatter;
|
||||
Assert.Same(serializerSettings, jsonFormatter.SerializerSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.Logging;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -28,18 +22,12 @@ namespace Microsoft.AspNet.Mvc
|
|||
= new byte[] { 123, 13, 10, 32, 32, 34, 102, 111, 111, 34, 58, 32, 34, 97, 98, 99, 100, 34, 13, 10, 125 };
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_OptionsFormatter_WithoutBOM()
|
||||
public async Task ExecuteResultAsync_UsesDefaultContentType_IfNoContentTypeSpecified()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var optionsFormatters = new List<IOutputFormatter>()
|
||||
{
|
||||
Mock.Of<IOutputFormatter>(), // This won't be used
|
||||
new JsonOutputFormatter(),
|
||||
};
|
||||
|
||||
var context = GetHttpContext(optionsFormatters);
|
||||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
|
|
@ -54,49 +42,16 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_Null()
|
||||
public async Task ExecuteResultAsync_NullEncoding_SetsContentTypeAndDefaultEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var optionsFormatters = new List<IOutputFormatter>()
|
||||
{
|
||||
Mock.Of<IOutputFormatter>(), // This won't be used
|
||||
new JsonOutputFormatter(),
|
||||
};
|
||||
|
||||
var context = GetHttpContext(optionsFormatters);
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_OptionsFormatter_Conneg()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var optionsFormatters = new List<IOutputFormatter>()
|
||||
{
|
||||
Mock.Of<IOutputFormatter>(), // This won't be used
|
||||
new JsonOutputFormatter(),
|
||||
};
|
||||
|
||||
var context = GetHttpContext(optionsFormatters);
|
||||
context.Request.Headers["Accept"] = "text/json";
|
||||
|
||||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
result.ContentType = new MediaTypeHeaderValue("text/json");
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
|
@ -108,7 +63,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_UsesPassedInFormatter()
|
||||
public async Task ExecuteResultAsync_SetsContentTypeAndEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
|
@ -116,13 +71,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var formatter = new JsonOutputFormatter();
|
||||
formatter.SupportedEncodings.Clear();
|
||||
|
||||
// This is UTF-8 WITH BOM
|
||||
formatter.SupportedEncodings.Add(Encoding.UTF8);
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" }, formatter);
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
result.ContentType = new MediaTypeHeaderValue("text/json")
|
||||
{
|
||||
Encoding = Encoding.ASCII
|
||||
};
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
|
|
@ -130,31 +83,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_UsesPassedInFormatter_ContentTypeSpecified()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var formatter = new JsonOutputFormatter();
|
||||
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/hal+json"));
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" }, formatter);
|
||||
result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/hal+json"));
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/hal+json; charset=utf-8", context.Response.ContentType);
|
||||
Assert.Equal("text/json; charset=us-ascii", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -180,67 +109,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
}
|
||||
|
||||
// If no formatter in options can match the given content-types, then use the one registered
|
||||
// in services
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_UsesGlobalFormatter_IfNoFormatterIsConfigured()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var context = GetHttpContext(enableFallback: true);
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
}
|
||||
|
||||
private HttpContext GetHttpContext(
|
||||
IReadOnlyList<IOutputFormatter> outputFormatters = null,
|
||||
bool enableFallback = false)
|
||||
private HttpContext GetHttpContext()
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
|
||||
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
|
||||
httpContext.RequestServices = services.Object;
|
||||
|
||||
var options = new MvcOptions();
|
||||
if (outputFormatters != null)
|
||||
{
|
||||
foreach (var formatter in outputFormatters)
|
||||
{
|
||||
options.OutputFormatters.Add(formatter);
|
||||
}
|
||||
}
|
||||
|
||||
var optionsAccessor = new Mock<IOptions<MvcOptions>>();
|
||||
optionsAccessor.SetupGet(o => o.Options)
|
||||
.Returns(options);
|
||||
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(optionsAccessor.Object);
|
||||
services.Setup(s => s.GetService(typeof(IOptions<MvcOptions>)))
|
||||
.Returns(optionsAccessor.Object);
|
||||
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
|
||||
.Returns(new Mock<ILogger<ObjectResult>>().Object);
|
||||
|
||||
// This is the ultimate fallback, it will be used if none of the formatters from options
|
||||
// work.
|
||||
if (enableFallback)
|
||||
{
|
||||
services
|
||||
.Setup(s => s.GetService(typeof(JsonOutputFormatter)))
|
||||
.Returns(new JsonOutputFormatter());
|
||||
}
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
// 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 Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.AspNet.Mvc.ViewComponents;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
|
@ -17,26 +16,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class JsonViewComponentResultTest
|
||||
{
|
||||
[Fact]
|
||||
public void Execute_SerializesData_UsingSpecifiedFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var view = Mock.Of<IView>();
|
||||
var buffer = new MemoryStream();
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
|
||||
var expectedFormatter = new JsonOutputFormatter();
|
||||
var result = new JsonViewComponentResult(1, expectedFormatter);
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedFormatter, result.Formatter);
|
||||
Assert.Equal("1", new StreamReader(buffer).ReadToEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_UsesFormatter_WithSpecifiedSerializerSettings()
|
||||
{
|
||||
|
|
@ -48,65 +27,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
var serializerSettings = new JsonSerializerSettings();
|
||||
serializerSettings.Formatting = Formatting.Indented;
|
||||
|
||||
var result = new JsonViewComponentResult("abc", serializerSettings);
|
||||
var result = new JsonViewComponentResult(new { foo = "abcd" }, serializerSettings);
|
||||
viewComponentContext.ViewContext.HttpContext.Response.Body = buffer;
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
|
||||
// Assert
|
||||
Assert.Same(serializerSettings, result.Formatter.SerializerSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_FallsbackToServices_WhenNoJsonFormatterIsProvided()
|
||||
{
|
||||
// Arrange
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var serviceProvider = new Mock<IServiceProvider>();
|
||||
|
||||
serviceProvider
|
||||
.Setup(p => p.GetService(typeof(JsonOutputFormatter)))
|
||||
.Returns(new JsonOutputFormatter())
|
||||
.Verifiable();
|
||||
|
||||
var buffer = new MemoryStream();
|
||||
|
||||
var result = new JsonViewComponentResult(1);
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider.Object;
|
||||
|
||||
// Act
|
||||
result.Execute(viewComponentContext);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Assert
|
||||
Assert.Equal("1", new StreamReader(buffer).ReadToEnd());
|
||||
serviceProvider.Verify();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_Throws_IfNoFormatterCanBeResolved()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "No service for type 'Microsoft.AspNet.Mvc.JsonOutputFormatter'" +
|
||||
" has been registered.";
|
||||
|
||||
var view = Mock.Of<IView>();
|
||||
|
||||
var serviceProvider = new ServiceCollection().BuildServiceProvider();
|
||||
|
||||
var buffer = new MemoryStream();
|
||||
|
||||
var result = new JsonViewComponentResult(1);
|
||||
var viewComponentContext = GetViewComponentContext(view, buffer);
|
||||
viewComponentContext.ViewContext.HttpContext.RequestServices = serviceProvider;
|
||||
|
||||
// Act
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => result.Execute(viewComponentContext));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, ex.Message);
|
||||
Assert.Equal("{\r\n \"foo\": \"abcd\"\r\n}", Encoding.UTF8.GetString(buffer.ToArray()));
|
||||
}
|
||||
|
||||
private static ViewComponentContext GetViewComponentContext(IView view, Stream stream)
|
||||
|
|
|
|||
|
|
@ -319,80 +319,6 @@ END:VCARD
|
|||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task JsonResult_UsesDefaultContentTypes_IfNoneAreAddedExplicitly()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
|
||||
var expectedBody = "{\"MethodName\":\"ReturnJsonResult\"}";
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task JsonResult_UsesExplicitContentTypeAndFormatter_IfAdded()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/custom-json;charset=utf-8");
|
||||
var expectedBody = "{ MethodName = ReturnJsonResult_WithCustomMediaType }";
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult_WithCustomMediaType");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task JsonResult_UsesDefaultJsonFormatter_IfNoMatchingFormatterIsFound()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
|
||||
var expectedBody = "{\"MethodName\":\"ReturnJsonResult_WithCustomMediaType_NoFormatter\"}";
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult_WithCustomMediaType_NoFormatter");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task JsonFormatter_SupportedMediaType_DoesNotChangeAcrossRequests()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
|
||||
var expectedBody = "{\"MethodName\":\"ReturnJsonResult\"}";
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
// Act and Assert
|
||||
var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult");
|
||||
|
||||
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedBody, body);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task XmlFormatter_SupportedMediaType_DoesNotChangeAcrossRequests()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
private readonly Action<IApplicationBuilder> _app = new BasicWebSite.Startup().Configure;
|
||||
private readonly Action<IServiceCollection> _configureServices = new BasicWebSite.Startup().ConfigureServices;
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("text/json")]
|
||||
public async Task JsonResult_Conneg(string mediaType)
|
||||
[Fact]
|
||||
public async Task JsonResult_UsesDefaultContentType()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
|
|
@ -29,7 +27,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
var url = "http://localhost/JsonResult/Plain";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.TryAddWithoutValidation("Accept", mediaType);
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
|
@ -37,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(mediaType, response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("{\"Message\":\"hello\"}", content);
|
||||
}
|
||||
|
||||
|
|
@ -111,56 +108,6 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
Assert.Equal("\"hello\"", content);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/json")]
|
||||
[InlineData("text/json")]
|
||||
public async Task JsonResult_CustomFormatter_Conneg(string mediaType)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var url = "http://localhost/JsonResult/CustomFormatter";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.TryAddWithoutValidation("Accept", mediaType);
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(mediaType, response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("{\"message\":\"hello\"}", content);
|
||||
}
|
||||
|
||||
// Using an Accept header can't force Json to not be Json. If your accept header doesn't jive with the
|
||||
// formatters/content-type configured on the result it will be ignored.
|
||||
[Theory]
|
||||
[InlineData("application/xml")]
|
||||
[InlineData("text/xml")]
|
||||
public async Task JsonResult_CustomFormatter_Conneg_Fails(string mediaType)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var url = "http://localhost/JsonResult/CustomFormatter";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.TryAddWithoutValidation("Accept", mediaType);
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
|
||||
Assert.Equal("{\"message\":\"hello\"}", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task JsonResult_Uses_CustomSerializerSettings()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -250,26 +250,7 @@ namespace System.Web.Http
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void ApiController_Json_Settings()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new ConcreteApiController();
|
||||
var product = new Product();
|
||||
var settings = new JsonSerializerSettings();
|
||||
|
||||
// Act
|
||||
var result = controller.Json(product, settings);
|
||||
|
||||
// Assert
|
||||
var jsonResult = Assert.IsType<JsonResult>(result);
|
||||
Assert.Same(product, jsonResult.Value);
|
||||
|
||||
var formatter = Assert.IsType<JsonOutputFormatter>(jsonResult.Formatter);
|
||||
Assert.Same(settings, formatter.SerializerSettings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApiController_Json_Settings_Encoding()
|
||||
public void ApiController_Json_Encoding()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new ConcreteApiController();
|
||||
|
|
@ -283,9 +264,7 @@ namespace System.Web.Http
|
|||
var jsonResult = Assert.IsType<JsonResult>(result);
|
||||
Assert.Same(product, jsonResult.Value);
|
||||
|
||||
var formatter = Assert.IsType<JsonOutputFormatter>(jsonResult.Formatter);
|
||||
Assert.Same(settings, formatter.SerializerSettings);
|
||||
Assert.Same(Encoding.UTF8, Assert.Single(formatter.SupportedEncodings));
|
||||
Assert.Same(Encoding.UTF8, jsonResult.ContentType.Encoding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -17,21 +17,10 @@ namespace BasicWebSite.Controllers
|
|||
return Json(new { Message = "hello" });
|
||||
}
|
||||
|
||||
public JsonResult CustomFormatter()
|
||||
{
|
||||
var formatter = new JsonOutputFormatter();
|
||||
formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
|
||||
|
||||
return new JsonResult(new { Message = "hello" }, formatter);
|
||||
}
|
||||
|
||||
public JsonResult CustomContentType()
|
||||
{
|
||||
var formatter = new JsonOutputFormatter();
|
||||
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/message+json"));
|
||||
|
||||
var result = new JsonResult(new { Message = "hello" }, formatter);
|
||||
result.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/message+json"));
|
||||
var result = new JsonResult(new { Message = "hello" });
|
||||
result.ContentType = MediaTypeHeaderValue.Parse("application/message+json");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,32 +2,11 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace ContentNegotiationWebSite
|
||||
{
|
||||
public class JsonResultController : Controller
|
||||
{
|
||||
public IActionResult ReturnJsonResult()
|
||||
{
|
||||
return new JsonResult(new { MethodName = "ReturnJsonResult" });
|
||||
}
|
||||
|
||||
public IActionResult ReturnJsonResult_WithCustomMediaType()
|
||||
{
|
||||
var jsonResult = new JsonResult(new { MethodName = "ReturnJsonResult_WithCustomMediaType" },
|
||||
new CustomFormatter("application/custom-json"));
|
||||
jsonResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/custom-json"));
|
||||
return jsonResult;
|
||||
}
|
||||
|
||||
public IActionResult ReturnJsonResult_WithCustomMediaType_NoFormatter()
|
||||
{
|
||||
var jsonResult = new JsonResult(new { MethodName = "ReturnJsonResult_WithCustomMediaType_NoFormatter" });
|
||||
jsonResult.ContentTypes.Add(MediaTypeHeaderValue.Parse("application/custom-json"));
|
||||
return jsonResult;
|
||||
}
|
||||
|
||||
[Produces("application/xml")]
|
||||
public IActionResult Produces_WithNonObjectResult()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue