66using System . Globalization ;
77using System . IO ;
88using Microsoft . AspNetCore . Html ;
9- using Microsoft . AspNetCore . Mvc . Formatters ;
109using Microsoft . AspNetCore . Mvc . Rendering ;
10+ using Microsoft . Extensions . Options ;
1111using Newtonsoft . Json ;
1212
1313namespace Microsoft . AspNetCore . Mvc . NewtonsoftJson
@@ -17,97 +17,74 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
1717 /// </summary>
1818 internal class NewtonsoftJsonHelper : IJsonHelper
1919 {
20- private readonly NewtonsoftJsonOutputFormatter _jsonOutputFormatter ;
21- private readonly ArrayPool < char > _charPool ;
20+ // Perf: JsonSerializers are relatively expensive to create, and are thread safe. Cache the serializer
21+ private readonly JsonSerializer _defaultSettingsJsonSerializer ;
22+ private readonly IArrayPool < char > _charPool ;
2223
2324 /// <summary>
24- /// Initializes a new instance of <see cref="NewtonsoftJsonHelper"/> that is backed by <paramref name="jsonOutputFormatter"/> .
25+ /// Initializes a new instance of <see cref="NewtonsoftJsonHelper"/>.
2526 /// </summary>
26- /// <param name="jsonOutputFormatter ">The <see cref="NewtonsoftJsonOutputFormatter "/> used to serialize JSON .</param>
27+ /// <param name="options ">The <see cref="MvcNewtonsoftJsonOptions "/>.</param>
2728 /// <param name="charPool">
2829 /// The <see cref="ArrayPool{Char}"/> for use with custom <see cref="JsonSerializerSettings"/> (see
2930 /// <see cref="Serialize(object, JsonSerializerSettings)"/>).
3031 /// </param>
31- public NewtonsoftJsonHelper ( NewtonsoftJsonOutputFormatter jsonOutputFormatter , ArrayPool < char > charPool )
32+ public NewtonsoftJsonHelper ( IOptions < MvcNewtonsoftJsonOptions > options , ArrayPool < char > charPool )
3233 {
33- if ( jsonOutputFormatter == null )
34+ if ( options == null )
3435 {
35- throw new ArgumentNullException ( nameof ( jsonOutputFormatter ) ) ;
36+ throw new ArgumentNullException ( nameof ( options ) ) ;
3637 }
38+
3739 if ( charPool == null )
3840 {
3941 throw new ArgumentNullException ( nameof ( charPool ) ) ;
4042 }
4143
42- _jsonOutputFormatter = jsonOutputFormatter ;
43- _charPool = charPool ;
44+ _defaultSettingsJsonSerializer = CreateHtmlSafeSerializer ( options . Value . SerializerSettings ) ;
45+ _charPool = new JsonArrayPool < char > ( charPool ) ;
4446 }
4547
46- /// <inheritdoc />
4748 public IHtmlContent Serialize ( object value )
4849 {
49- var settings = ShallowCopy ( _jsonOutputFormatter . PublicSerializerSettings ) ;
50- settings . StringEscapeHandling = StringEscapeHandling . EscapeHtml ;
51-
52- return Serialize ( value , settings ) ;
50+ return Serialize ( value , _defaultSettingsJsonSerializer ) ;
5351 }
5452
55- /// <inheritdoc />
5653 public IHtmlContent Serialize ( object value , JsonSerializerSettings serializerSettings )
5754 {
5855 if ( serializerSettings == null )
5956 {
6057 throw new ArgumentNullException ( nameof ( serializerSettings ) ) ;
6158 }
6259
63- var jsonOutputFormatter = new NewtonsoftJsonOutputFormatter ( serializerSettings , _charPool ) ;
64-
65- return SerializeInternal ( jsonOutputFormatter , value ) ;
60+ var jsonSerializer = CreateHtmlSafeSerializer ( serializerSettings ) ;
61+ return Serialize ( value , jsonSerializer ) ;
6662 }
6763
68- private IHtmlContent SerializeInternal ( NewtonsoftJsonOutputFormatter jsonOutputFormatter , object value )
64+ private IHtmlContent Serialize ( object value , JsonSerializer jsonSerializer )
6965 {
70- var stringWriter = new StringWriter ( CultureInfo . InvariantCulture ) ;
71- jsonOutputFormatter . WriteObject ( stringWriter , value ) ;
66+ using ( var stringWriter = new StringWriter ( CultureInfo . InvariantCulture ) )
67+ {
68+ var jsonWriter = new JsonTextWriter ( stringWriter )
69+ {
70+ ArrayPool = _charPool ,
71+ } ;
7272
73- return new HtmlString ( stringWriter . ToString ( ) ) ;
73+ using ( jsonWriter )
74+ {
75+ jsonSerializer . Serialize ( jsonWriter , value ) ;
76+ }
77+
78+ return new HtmlString ( stringWriter . ToString ( ) ) ;
79+ }
7480 }
7581
76- private static JsonSerializerSettings ShallowCopy ( JsonSerializerSettings settings )
82+ private static JsonSerializer CreateHtmlSafeSerializer ( JsonSerializerSettings serializerSettings )
7783 {
78- var copiedSettings = new JsonSerializerSettings
79- {
80- FloatParseHandling = settings . FloatParseHandling ,
81- FloatFormatHandling = settings . FloatFormatHandling ,
82- DateParseHandling = settings . DateParseHandling ,
83- DateTimeZoneHandling = settings . DateTimeZoneHandling ,
84- DateFormatHandling = settings . DateFormatHandling ,
85- Formatting = settings . Formatting ,
86- MaxDepth = settings . MaxDepth ,
87- DateFormatString = settings . DateFormatString ,
88- Context = settings . Context ,
89- Error = settings . Error ,
90- SerializationBinder = settings . SerializationBinder ,
91- TraceWriter = settings . TraceWriter ,
92- Culture = settings . Culture ,
93- ReferenceResolverProvider = settings . ReferenceResolverProvider ,
94- EqualityComparer = settings . EqualityComparer ,
95- ContractResolver = settings . ContractResolver ,
96- ConstructorHandling = settings . ConstructorHandling ,
97- TypeNameAssemblyFormatHandling = settings . TypeNameAssemblyFormatHandling ,
98- MetadataPropertyHandling = settings . MetadataPropertyHandling ,
99- TypeNameHandling = settings . TypeNameHandling ,
100- PreserveReferencesHandling = settings . PreserveReferencesHandling ,
101- Converters = settings . Converters ,
102- DefaultValueHandling = settings . DefaultValueHandling ,
103- NullValueHandling = settings . NullValueHandling ,
104- ObjectCreationHandling = settings . ObjectCreationHandling ,
105- MissingMemberHandling = settings . MissingMemberHandling ,
106- ReferenceLoopHandling = settings . ReferenceLoopHandling ,
107- CheckAdditionalContent = settings . CheckAdditionalContent ,
108- } ;
109-
110- return copiedSettings ;
84+ var jsonSerializer = JsonSerializer . Create ( serializerSettings ) ;
85+ // Ignore the user configured StringEscapeHandling and always escape it.
86+ jsonSerializer . StringEscapeHandling = StringEscapeHandling . EscapeHtml ;
87+ return jsonSerializer ;
11188 }
11289 }
11390}
0 commit comments