6
6
using System . Globalization ;
7
7
using System . IO ;
8
8
using Microsoft . AspNetCore . Html ;
9
- using Microsoft . AspNetCore . Mvc . Formatters ;
10
9
using Microsoft . AspNetCore . Mvc . Rendering ;
10
+ using Microsoft . Extensions . Options ;
11
11
using Newtonsoft . Json ;
12
12
13
13
namespace Microsoft . AspNetCore . Mvc . NewtonsoftJson
@@ -17,97 +17,74 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
17
17
/// </summary>
18
18
internal class NewtonsoftJsonHelper : IJsonHelper
19
19
{
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 ;
22
23
23
24
/// <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"/>.
25
26
/// </summary>
26
- /// <param name="jsonOutputFormatter ">The <see cref="NewtonsoftJsonOutputFormatter "/> used to serialize JSON .</param>
27
+ /// <param name="options ">The <see cref="MvcNewtonsoftJsonOptions "/>.</param>
27
28
/// <param name="charPool">
28
29
/// The <see cref="ArrayPool{Char}"/> for use with custom <see cref="JsonSerializerSettings"/> (see
29
30
/// <see cref="Serialize(object, JsonSerializerSettings)"/>).
30
31
/// </param>
31
- public NewtonsoftJsonHelper ( NewtonsoftJsonOutputFormatter jsonOutputFormatter , ArrayPool < char > charPool )
32
+ public NewtonsoftJsonHelper ( IOptions < MvcNewtonsoftJsonOptions > options , ArrayPool < char > charPool )
32
33
{
33
- if ( jsonOutputFormatter == null )
34
+ if ( options == null )
34
35
{
35
- throw new ArgumentNullException ( nameof ( jsonOutputFormatter ) ) ;
36
+ throw new ArgumentNullException ( nameof ( options ) ) ;
36
37
}
38
+
37
39
if ( charPool == null )
38
40
{
39
41
throw new ArgumentNullException ( nameof ( charPool ) ) ;
40
42
}
41
43
42
- _jsonOutputFormatter = jsonOutputFormatter ;
43
- _charPool = charPool ;
44
+ _defaultSettingsJsonSerializer = CreateHtmlSafeSerializer ( options . Value . SerializerSettings ) ;
45
+ _charPool = new JsonArrayPool < char > ( charPool ) ;
44
46
}
45
47
46
- /// <inheritdoc />
47
48
public IHtmlContent Serialize ( object value )
48
49
{
49
- var settings = ShallowCopy ( _jsonOutputFormatter . PublicSerializerSettings ) ;
50
- settings . StringEscapeHandling = StringEscapeHandling . EscapeHtml ;
51
-
52
- return Serialize ( value , settings ) ;
50
+ return Serialize ( value , _defaultSettingsJsonSerializer ) ;
53
51
}
54
52
55
- /// <inheritdoc />
56
53
public IHtmlContent Serialize ( object value , JsonSerializerSettings serializerSettings )
57
54
{
58
55
if ( serializerSettings == null )
59
56
{
60
57
throw new ArgumentNullException ( nameof ( serializerSettings ) ) ;
61
58
}
62
59
63
- var jsonOutputFormatter = new NewtonsoftJsonOutputFormatter ( serializerSettings , _charPool ) ;
64
-
65
- return SerializeInternal ( jsonOutputFormatter , value ) ;
60
+ var jsonSerializer = CreateHtmlSafeSerializer ( serializerSettings ) ;
61
+ return Serialize ( value , jsonSerializer ) ;
66
62
}
67
63
68
- private IHtmlContent SerializeInternal ( NewtonsoftJsonOutputFormatter jsonOutputFormatter , object value )
64
+ private IHtmlContent Serialize ( object value , JsonSerializer jsonSerializer )
69
65
{
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
+ } ;
72
72
73
- return new HtmlString ( stringWriter . ToString ( ) ) ;
73
+ using ( jsonWriter )
74
+ {
75
+ jsonSerializer . Serialize ( jsonWriter , value ) ;
76
+ }
77
+
78
+ return new HtmlString ( stringWriter . ToString ( ) ) ;
79
+ }
74
80
}
75
81
76
- private static JsonSerializerSettings ShallowCopy ( JsonSerializerSettings settings )
82
+ private static JsonSerializer CreateHtmlSafeSerializer ( JsonSerializerSettings serializerSettings )
77
83
{
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 ;
111
88
}
112
89
}
113
90
}
0 commit comments