Add buffer pooling to JsonResult
This commit is contained in:
parent
3da2c35e3e
commit
ece6ecde45
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -52,6 +53,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcJsonMvcOptionsSetup>());
|
||||
services.TryAddSingleton<JsonResultExecutor>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
// 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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.Mvc.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// Executes a <see cref="JsonResult"/> to write to the response.
|
||||
/// </summary>
|
||||
public class JsonResultExecutor
|
||||
{
|
||||
private static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("application/json")
|
||||
{
|
||||
Encoding = Encoding.UTF8
|
||||
}.CopyAsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="JsonResultExecutor"/>.
|
||||
/// </summary>
|
||||
/// <param name="writerFactory">The <see cref="IHttpResponseStreamWriterFactory"/>.</param>
|
||||
/// <param name="logger">The <see cref="ILogger{JsonResultExecutor}"/>.</param>
|
||||
/// <param name="options">The <see cref="IOptions{MvcJsonOptions}"/>.</param>
|
||||
public JsonResultExecutor(
|
||||
IHttpResponseStreamWriterFactory writerFactory,
|
||||
ILogger<JsonResultExecutor> logger,
|
||||
IOptions<MvcJsonOptions> options)
|
||||
{
|
||||
if (writerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writerFactory));
|
||||
}
|
||||
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
WriterFactory = writerFactory;
|
||||
Logger = logger;
|
||||
Options = options.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ILogger"/>.
|
||||
/// </summary>
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="MvcJsonOptions"/>.
|
||||
/// </summary>
|
||||
protected MvcJsonOptions Options { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IHttpResponseStreamWriterFactory"/>.
|
||||
/// </summary>
|
||||
protected IHttpResponseStreamWriterFactory WriterFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Executes the <see cref="JsonResult"/> and writes the response.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActionContext"/>.</param>
|
||||
/// <param name="result">The <see cref="JsonResult"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> which will complete when writing has completed.</returns>
|
||||
public Task ExecuteAsync(ActionContext context, JsonResult result)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(result));
|
||||
}
|
||||
|
||||
var response = context.HttpContext.Response;
|
||||
|
||||
string resolvedContentType = null;
|
||||
Encoding resolvedContentTypeEncoding = null;
|
||||
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
|
||||
result.ContentType,
|
||||
response.ContentType,
|
||||
DefaultContentType,
|
||||
out resolvedContentType,
|
||||
out resolvedContentTypeEncoding);
|
||||
|
||||
response.ContentType = resolvedContentType;
|
||||
|
||||
if (result.StatusCode != null)
|
||||
{
|
||||
response.StatusCode = result.StatusCode.Value;
|
||||
}
|
||||
|
||||
var serializerSettings = result.SerializerSettings ?? Options.SerializerSettings;
|
||||
|
||||
Logger.JsonResultExecuting(result.Value);
|
||||
using (var writer = WriterFactory.CreateWriter(response.Body, resolvedContentTypeEncoding))
|
||||
{
|
||||
using (var jsonWriter = new JsonTextWriter(writer))
|
||||
{
|
||||
jsonWriter.CloseOutput = false;
|
||||
|
||||
var jsonSerializer = JsonSerializer.Create(serializerSettings);
|
||||
jsonSerializer.Serialize(jsonWriter, result.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return TaskCache.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,11 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Internal;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.AspNet.Mvc.Logging;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
|
|
@ -19,13 +15,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public class JsonResult : ActionResult
|
||||
{
|
||||
private readonly JsonSerializerSettings _serializerSettings;
|
||||
|
||||
private static readonly MediaTypeHeaderValue DefaultContentType = new MediaTypeHeaderValue("application/json")
|
||||
{
|
||||
Encoding = Encoding.UTF8
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="JsonResult"/> with the given <paramref name="value"/>.
|
||||
/// </summary>
|
||||
|
|
@ -49,7 +38,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
|
||||
Value = value;
|
||||
_serializerSettings = serializerSettings;
|
||||
SerializerSettings = serializerSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -57,6 +46,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public MediaTypeHeaderValue ContentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="JsonSerializerSettings"/>.
|
||||
/// </summary>
|
||||
public JsonSerializerSettings SerializerSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the HTTP status code.
|
||||
/// </summary>
|
||||
|
|
@ -75,50 +69,9 @@ namespace Microsoft.AspNet.Mvc
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var loggerFactory = context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>();
|
||||
var logger = loggerFactory.CreateLogger<JsonResult>();
|
||||
|
||||
var response = context.HttpContext.Response;
|
||||
|
||||
string resolvedContentType = null;
|
||||
Encoding resolvedContentTypeEncoding = null;
|
||||
ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
|
||||
ContentType,
|
||||
response.ContentType,
|
||||
DefaultContentType,
|
||||
out resolvedContentType,
|
||||
out resolvedContentTypeEncoding);
|
||||
|
||||
response.ContentType = resolvedContentType;
|
||||
|
||||
if (StatusCode != null)
|
||||
{
|
||||
response.StatusCode = StatusCode.Value;
|
||||
}
|
||||
|
||||
var serializerSettings = _serializerSettings;
|
||||
if (serializerSettings == null)
|
||||
{
|
||||
serializerSettings = context
|
||||
.HttpContext
|
||||
.RequestServices
|
||||
.GetRequiredService<IOptions<MvcJsonOptions>>()
|
||||
.Value
|
||||
.SerializerSettings;
|
||||
}
|
||||
|
||||
logger.JsonResultExecuting(Value);
|
||||
using (var writer = new HttpResponseStreamWriter(response.Body, resolvedContentTypeEncoding))
|
||||
{
|
||||
using (var jsonWriter = new JsonTextWriter(writer))
|
||||
{
|
||||
jsonWriter.CloseOutput = false;
|
||||
var jsonSerializer = JsonSerializer.Create(serializerSettings);
|
||||
jsonSerializer.Serialize(jsonWriter, Value);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
var services = context.HttpContext.RequestServices;
|
||||
var executor = services.GetRequiredService<JsonResultExecutor>();
|
||||
return executor.ExecuteAsync(context, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc.Logging
|
||||
{
|
||||
internal static class JsonResultLoggerExtensions
|
||||
internal static class JsonResultExecutorLoggerExtensions
|
||||
{
|
||||
private static readonly Action<ILogger, string, Exception> _jsonResultExecuting;
|
||||
|
||||
static JsonResultLoggerExtensions()
|
||||
static JsonResultExecutorLoggerExtensions()
|
||||
{
|
||||
_jsonResultExecuting = LoggerMessage.Define<string>(
|
||||
LogLevel.Information,
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
// 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.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Infrastructure
|
||||
{
|
||||
public class JsonResultExecutorTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_UsesDefaultContentType_IfNoContentTypeSpecified()
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
|
||||
|
||||
var context = GetActionContext();
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_NullEncoding_DoesNotSetCharsetOnContentType()
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
|
||||
|
||||
var context = GetActionContext();
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
result.ContentType = new MediaTypeHeaderValue("text/json");
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("text/json", context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_SetsContentTypeAndEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
|
||||
|
||||
var context = GetActionContext();
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
result.ContentType = new MediaTypeHeaderValue("text/json")
|
||||
{
|
||||
Encoding = Encoding.ASCII
|
||||
};
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("text/json; charset=us-ascii", context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_NoResultContentTypeSet_UsesResponseContentType_AndSuppliedEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
|
||||
var expectedContentType = "text/foo; p1=p1-value; charset=us-ascii";
|
||||
|
||||
var context = GetActionContext();
|
||||
context.HttpContext.Response.ContentType = expectedContentType;
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal(expectedContentType, context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("text/foo", "text/foo")]
|
||||
[InlineData("text/foo; p1=p1-value", "text/foo; p1=p1-value")]
|
||||
public async Task ExecuteAsync_NoResultContentTypeSet_UsesDefaultEncoding_DoesNotSetCharset(
|
||||
string responseContentType,
|
||||
string expectedContentType)
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
|
||||
|
||||
var context = GetActionContext();
|
||||
context.HttpContext.Response.ContentType = responseContentType;
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal(expectedContentType, context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_UsesPassedInSerializerSettings()
|
||||
{
|
||||
// Arrange
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(
|
||||
new { foo = "abcd" },
|
||||
Formatting.Indented));
|
||||
|
||||
var context = GetActionContext();
|
||||
|
||||
var serializerSettings = new JsonSerializerSettings();
|
||||
serializerSettings.Formatting = Formatting.Indented;
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" }, serializerSettings);
|
||||
var executor = CreateExcutor();
|
||||
|
||||
// Act
|
||||
await executor.ExecuteAsync(context, result);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
private static JsonResultExecutor CreateExcutor()
|
||||
{
|
||||
return new JsonResultExecutor(
|
||||
new TestHttpResponseStreamWriterFactory(),
|
||||
NullLogger<JsonResultExecutor>.Instance,
|
||||
new TestOptionsManager<MvcJsonOptions>());
|
||||
}
|
||||
|
||||
private static HttpContext GetHttpContext()
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddOptions();
|
||||
services.AddInstance<ILoggerFactory>(NullLoggerFactory.Instance);
|
||||
httpContext.RequestServices = services.BuildServiceProvider();
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private static ActionContext GetActionContext()
|
||||
{
|
||||
return new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
}
|
||||
|
||||
private static byte[] GetWrittenBytes(HttpContext context)
|
||||
{
|
||||
context.Response.Body.Seek(0, SeekOrigin.Begin);
|
||||
return Assert.IsType<MemoryStream>(context.Response.Body).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,16 @@
|
|||
// 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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
using Microsoft.AspNet.Mvc.Abstractions;
|
||||
using Microsoft.AspNet.Mvc.Infrastructure;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -21,155 +18,24 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
public class JsonResultTest
|
||||
{
|
||||
private static readonly byte[] _abcdUTF8Bytes
|
||||
= new byte[] { 123, 34, 102, 111, 111, 34, 58, 34, 97, 98, 99, 100, 34, 125 };
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_UsesDefaultContentType_IfNoContentTypeSpecified()
|
||||
public async Task ExecuteAsync_WritesJsonContent()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
var value = new { foo = "abcd" };
|
||||
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
|
||||
|
||||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
var context = GetActionContext();
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" });
|
||||
var result = new JsonResult(value);
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
await result.ExecuteResultAsync(context);
|
||||
|
||||
// Assert
|
||||
var written = GetWrittenBytes(context.HttpContext);
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_NullEncoding_DoesNotSetCharsetOnContentType()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
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);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("text/json", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_SetsContentTypeAndEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
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")
|
||||
{
|
||||
Encoding = Encoding.ASCII
|
||||
};
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("text/json; charset=us-ascii", context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NoResultContentTypeSet_UsesResponseContentType_AndSuppliedEncoding()
|
||||
{
|
||||
// Arrange
|
||||
var expectedData = Encoding.ASCII.GetBytes("{\"foo\":\"abcd\"}");
|
||||
var expectedContentType = "text/foo; p1=p1-value; charset=us-ascii";
|
||||
var context = GetHttpContext();
|
||||
context.Response.ContentType = expectedContentType;
|
||||
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(expectedData, written);
|
||||
Assert.Equal(expectedContentType, context.Response.ContentType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("text/foo", "text/foo")]
|
||||
[InlineData("text/foo; p1=p1-value", "text/foo; p1=p1-value")]
|
||||
public async Task NoResultContentTypeSet_UsesResponseContentTypeAndDefaultEncoding_DoesNotSetCharset(
|
||||
string responseContentType,
|
||||
string expectedContentType)
|
||||
{
|
||||
// Arrange
|
||||
var expected = _abcdUTF8Bytes;
|
||||
|
||||
var context = GetHttpContext();
|
||||
context.Response.ContentType = responseContentType;
|
||||
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(expectedContentType, context.Response.ContentType);
|
||||
}
|
||||
|
||||
private static List<byte> AbcdIndentedUTF8Bytes
|
||||
{
|
||||
get
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
bytes.Add(123);
|
||||
bytes.AddRange(Encoding.UTF8.GetBytes(Environment.NewLine));
|
||||
bytes.AddRange(new byte[] { 32, 32, 34, 102, 111, 111, 34, 58, 32, 34, 97, 98, 99, 100, 34 });
|
||||
bytes.AddRange(Encoding.UTF8.GetBytes(Environment.NewLine));
|
||||
bytes.Add(125);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteResultAsync_UsesPassedInSerializerSettings()
|
||||
{
|
||||
// Arrange
|
||||
var expected = AbcdIndentedUTF8Bytes;
|
||||
|
||||
var context = GetHttpContext();
|
||||
var actionContext = new ActionContext(context, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var serializerSettings = new JsonSerializerSettings();
|
||||
serializerSettings.Formatting = Formatting.Indented;
|
||||
|
||||
var result = new JsonResult(new { foo = "abcd" }, serializerSettings);
|
||||
|
||||
// Act
|
||||
await result.ExecuteResultAsync(actionContext);
|
||||
var written = GetWrittenBytes(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, written);
|
||||
Assert.Equal("application/json; charset=utf-8", context.Response.ContentType);
|
||||
Assert.Equal("application/json; charset=utf-8", context.HttpContext.Response.ContentType);
|
||||
}
|
||||
|
||||
private static HttpContext GetHttpContext()
|
||||
|
|
@ -177,14 +43,23 @@ namespace Microsoft.AspNet.Mvc
|
|||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.Response.Body = new MemoryStream();
|
||||
|
||||
var executor = new JsonResultExecutor(
|
||||
new TestHttpResponseStreamWriterFactory(),
|
||||
NullLogger<JsonResultExecutor>.Instance,
|
||||
new TestOptionsManager<MvcJsonOptions>());
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddOptions();
|
||||
services.AddInstance<ILoggerFactory>(NullLoggerFactory.Instance);
|
||||
services.AddInstance(executor);
|
||||
httpContext.RequestServices = services.BuildServiceProvider();
|
||||
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
private static ActionContext GetActionContext()
|
||||
{
|
||||
return new ActionContext(GetHttpContext(), new RouteData(), new ActionDescriptor());
|
||||
}
|
||||
|
||||
private static byte[] GetWrittenBytes(HttpContext context)
|
||||
{
|
||||
context.Response.Body.Seek(0, SeekOrigin.Begin);
|
||||
|
|
|
|||
Loading…
Reference in New Issue