Merged PR 7269: Avoid caching JsonSerializer
Avoid caching JsonSerializer
This commit is contained in:
parent
45a57eac45
commit
23c02ef9a9
|
|
@ -20,10 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
{
|
{
|
||||||
private readonly IArrayPool<char> _charPool;
|
private readonly IArrayPool<char> _charPool;
|
||||||
private readonly MvcOptions _mvcOptions;
|
private readonly MvcOptions _mvcOptions;
|
||||||
|
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;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new <see cref="NewtonsoftJsonOutputFormatter"/> instance.
|
/// Initializes a new <see cref="NewtonsoftJsonOutputFormatter"/> instance.
|
||||||
|
|
@ -99,12 +96,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
/// <returns>The <see cref="JsonSerializer"/> used during serialization and deserialization.</returns>
|
||||||
protected virtual JsonSerializer CreateJsonSerializer()
|
protected virtual JsonSerializer CreateJsonSerializer()
|
||||||
{
|
{
|
||||||
if (_serializer == null)
|
if (_serializerSettings == null)
|
||||||
{
|
{
|
||||||
_serializer = JsonSerializer.Create(SerializerSettings);
|
// Lock the serializer settings once the first serialization has been initiated.
|
||||||
|
_serializerSettings = ShallowCopy(SerializerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _serializer;
|
return JsonSerializer.Create(_serializerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -166,5 +164,43 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static JsonSerializerSettings ShallowCopy(JsonSerializerSettings settings)
|
||||||
|
{
|
||||||
|
var copiedSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
FloatParseHandling = settings.FloatParseHandling,
|
||||||
|
FloatFormatHandling = settings.FloatFormatHandling,
|
||||||
|
DateParseHandling = settings.DateParseHandling,
|
||||||
|
DateTimeZoneHandling = settings.DateTimeZoneHandling,
|
||||||
|
DateFormatHandling = settings.DateFormatHandling,
|
||||||
|
Formatting = settings.Formatting,
|
||||||
|
MaxDepth = settings.MaxDepth,
|
||||||
|
DateFormatString = settings.DateFormatString,
|
||||||
|
Context = settings.Context,
|
||||||
|
Error = settings.Error,
|
||||||
|
SerializationBinder = settings.SerializationBinder,
|
||||||
|
TraceWriter = settings.TraceWriter,
|
||||||
|
Culture = settings.Culture,
|
||||||
|
ReferenceResolverProvider = settings.ReferenceResolverProvider,
|
||||||
|
EqualityComparer = settings.EqualityComparer,
|
||||||
|
ContractResolver = settings.ContractResolver,
|
||||||
|
ConstructorHandling = settings.ConstructorHandling,
|
||||||
|
TypeNameAssemblyFormatHandling = settings.TypeNameAssemblyFormatHandling,
|
||||||
|
MetadataPropertyHandling = settings.MetadataPropertyHandling,
|
||||||
|
TypeNameHandling = settings.TypeNameHandling,
|
||||||
|
PreserveReferencesHandling = settings.PreserveReferencesHandling,
|
||||||
|
Converters = settings.Converters,
|
||||||
|
DefaultValueHandling = settings.DefaultValueHandling,
|
||||||
|
NullValueHandling = settings.NullValueHandling,
|
||||||
|
ObjectCreationHandling = settings.ObjectCreationHandling,
|
||||||
|
MissingMemberHandling = settings.MissingMemberHandling,
|
||||||
|
ReferenceLoopHandling = settings.ReferenceLoopHandling,
|
||||||
|
CheckAdditionalContent = settings.CheckAdditionalContent,
|
||||||
|
StringEscapeHandling = settings.StringEscapeHandling,
|
||||||
|
};
|
||||||
|
|
||||||
|
return copiedSettings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,40 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
stream.Verify(v => v.Flush(), Times.Never());
|
stream.Verify(v => v.Flush(), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SerializingWithPreserveReferenceHandling()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "{\"$id\":\"1\",\"fullName\":\"John\",\"age\":35}";
|
||||||
|
var user = new User { FullName = "John", age = 35 };
|
||||||
|
|
||||||
|
var settings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ContractResolver = new DefaultContractResolver
|
||||||
|
{
|
||||||
|
NamingStrategy = new CamelCaseNamingStrategy(),
|
||||||
|
},
|
||||||
|
PreserveReferencesHandling = PreserveReferencesHandling.All,
|
||||||
|
};
|
||||||
|
var formatter = new TestableJsonOutputFormatter(settings);
|
||||||
|
|
||||||
|
for (var i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
// Act
|
||||||
|
var context = GetOutputFormatterContext(user, typeof(User));
|
||||||
|
await formatter.WriteResponseBodyAsync(context, Encoding.UTF8);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var body = context.HttpContext.Response.Body;
|
||||||
|
|
||||||
|
Assert.NotNull(body);
|
||||||
|
body.Position = 0;
|
||||||
|
|
||||||
|
var content = new StreamReader(body, Encoding.UTF8).ReadToEnd();
|
||||||
|
Assert.Equal(expected, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class TestableJsonOutputFormatter : NewtonsoftJsonOutputFormatter
|
private class TestableJsonOutputFormatter : NewtonsoftJsonOutputFormatter
|
||||||
{
|
{
|
||||||
public TestableJsonOutputFormatter(JsonSerializerSettings serializerSettings)
|
public TestableJsonOutputFormatter(JsonSerializerSettings serializerSettings)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue