diff --git a/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs
index 70ef8c2512..975ebf23b8 100644
--- a/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs
+++ b/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonOutputFormatter.cs
@@ -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
///
/// Gets or sets the used to configure the .
///
+ ///
+ /// Any modifications to the object after this
+ /// has been used will have no effect.
+ ///
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
/// The used during serialization and deserialization.
protected virtual JsonSerializer CreateJsonSerializer()
{
- return JsonSerializer.Create(SerializerSettings);
+ if (_serializer == null)
+ {
+ _serializer = JsonSerializer.Create(SerializerSettings);
+ }
+
+ return _serializer;
}
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context)
diff --git a/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs
index b748f0f9bf..d5fc0b8c76 100644
--- a/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Formatters.Json.Test/JsonOutputFormatterTests.cs
@@ -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()
{