Pool JsonSerializer for Output formatting

This commit is contained in:
Ryan Nowak 2015-11-16 10:43:02 -08:00
parent ccfd235f50
commit e75eebbed0
2 changed files with 91 additions and 1 deletions

View File

@ -17,6 +17,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
{
private JsonSerializerSettings _serializerSettings;
// Perf: JsonSerializers are relatively expensive to create, and are thread safe. We cache
// the serializer and invalidate it when the settings change.
private JsonSerializer _serializer;
public JsonOutputFormatter()
: this(SerializerSettingsProvider.CreateSerializerSettings())
{
@ -40,6 +44,10 @@ namespace Microsoft.AspNet.Mvc.Formatters
/// <summary>
/// Gets or sets the <see cref="JsonSerializerSettings"/> used to configure the <see cref="JsonSerializer"/>.
/// </summary>
/// <remarks>
/// Any modifications to the <see cref="JsonSerializerSettings"/> object after this
/// <see cref="JsonOutputFormatter"/> has been used will have no effect.
/// </remarks>
public JsonSerializerSettings SerializerSettings
{
get
@ -54,6 +62,9 @@ namespace Microsoft.AspNet.Mvc.Formatters
}
_serializerSettings = value;
// If the settings change, then invalidate the cached serializer.
_serializer = null;
}
}
@ -95,7 +106,12 @@ namespace Microsoft.AspNet.Mvc.Formatters
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
protected virtual JsonSerializer CreateJsonSerializer()
{
return JsonSerializer.Create(SerializerSettings);
if (_serializer == null)
{
_serializer = JsonSerializer.Create(SerializerSettings);
}
return _serializer;
}
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Testing;
using Microsoft.Net.Http.Headers;
@ -74,6 +75,79 @@ namespace Microsoft.AspNet.Mvc.Formatters
Assert.Equal(expectedOutput, content);
}
[Fact]
public async Task ChangesTo_DefaultSerializerSettings_AfterSerialization_NoEffect()
{
// Arrange
var person = new User() { Name = "John", Age = 35 };
var expectedOutput = JsonConvert.SerializeObject(
person,
SerializerSettingsProvider.CreateSerializerSettings());
var jsonFormatter = new JsonOutputFormatter();
// This will create a serializer - which gets cached.
var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User));
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext1);
// These changes should have no effect.
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
var outputFormatterContext2 = GetOutputFormatterContext(person, typeof(User));
// Act
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext2);
// Assert
var body = outputFormatterContext2.HttpContext.Response.Body;
Assert.NotNull(body);
body.Position = 0;
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
Assert.Equal(expectedOutput, content);
}
[Fact]
public async Task ReplaceSerializerSettings_AfterSerialization_TakesEffect()
{
// Arrange
var person = new User() { Name = "John", Age = 35 };
var expectedOutput = JsonConvert.SerializeObject(person, new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.Indented
});
var jsonFormatter = new JsonOutputFormatter();
// This will create a serializer - which gets cached.
var outputFormatterContext1 = GetOutputFormatterContext(person, typeof(User));
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext1);
// This results in a new serializer being created.
jsonFormatter.SerializerSettings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.Indented,
};
var outputFormatterContext2 = GetOutputFormatterContext(person, typeof(User));
// Act
await jsonFormatter.WriteResponseBodyAsync(outputFormatterContext2);
// Assert
var body = outputFormatterContext2.HttpContext.Response.Body;
Assert.NotNull(body);
body.Position = 0;
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
Assert.Equal(expectedOutput, content);
}
[Fact]
public async Task CustomSerializerSettingsObject_TakesEffect()
{