|
|
@@ -6,8 +6,8 @@ using System.Buffers;
|
|
|
using System.Globalization;
|
|
|
using System.IO;
|
|
|
using Microsoft.AspNetCore.Html;
|
|
|
-using Microsoft.AspNetCore.Mvc.Formatters;
|
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
|
+using Microsoft.Extensions.Options;
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
|
|
@@ -17,42 +17,39 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
|
|
/// </summary>
|
|
|
internal class NewtonsoftJsonHelper : IJsonHelper
|
|
|
{
|
|
|
- private readonly NewtonsoftJsonOutputFormatter _jsonOutputFormatter;
|
|
|
- private readonly ArrayPool<char> _charPool;
|
|
|
+ // Perf: JsonSerializers are relatively expensive to create, and are thread safe. Cache the serializer
|
|
|
+ private readonly JsonSerializer _defaultSettingsJsonSerializer;
|
|
|
+ private readonly IArrayPool<char> _charPool;
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Initializes a new instance of <see cref="NewtonsoftJsonHelper"/> that is backed by <paramref name="jsonOutputFormatter"/>.
|
|
|
+ /// Initializes a new instance of <see cref="NewtonsoftJsonHelper"/>.
|
|
|
/// </summary>
|
|
|
- /// <param name="jsonOutputFormatter">The <see cref="NewtonsoftJsonOutputFormatter"/> used to serialize JSON.</param>
|
|
|
+ /// <param name="options">The <see cref="MvcNewtonsoftJsonOptions"/>.</param>
|
|
|
/// <param name="charPool">
|
|
|
/// The <see cref="ArrayPool{Char}"/> for use with custom <see cref="JsonSerializerSettings"/> (see
|
|
|
/// <see cref="Serialize(object, JsonSerializerSettings)"/>).
|
|
|
/// </param>
|
|
|
- public NewtonsoftJsonHelper(NewtonsoftJsonOutputFormatter jsonOutputFormatter, ArrayPool<char> charPool)
|
|
|
+ public NewtonsoftJsonHelper(IOptions<MvcNewtonsoftJsonOptions> options, ArrayPool<char> charPool)
|
|
|
{
|
|
|
- if (jsonOutputFormatter == null)
|
|
|
+ if (options == null)
|
|
|
{
|
|
|
- throw new ArgumentNullException(nameof(jsonOutputFormatter));
|
|
|
+ throw new ArgumentNullException(nameof(options));
|
|
|
}
|
|
|
+
|
|
|
if (charPool == null)
|
|
|
{
|
|
|
throw new ArgumentNullException(nameof(charPool));
|
|
|
}
|
|
|
|
|
|
- _jsonOutputFormatter = jsonOutputFormatter;
|
|
|
- _charPool = charPool;
|
|
|
+ _defaultSettingsJsonSerializer = CreateHtmlSafeSerializer(options.Value.SerializerSettings);
|
|
|
+ _charPool = new JsonArrayPool<char>(charPool);
|
|
|
}
|
|
|
|
|
|
- /// <inheritdoc />
|
|
|
public IHtmlContent Serialize(object value)
|
|
|
{
|
|
|
- var settings = ShallowCopy(_jsonOutputFormatter.PublicSerializerSettings);
|
|
|
- settings.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
|
|
|
-
|
|
|
- return Serialize(value, settings);
|
|
|
+ return Serialize(value, _defaultSettingsJsonSerializer);
|
|
|
}
|
|
|
|
|
|
- /// <inheritdoc />
|
|
|
public IHtmlContent Serialize(object value, JsonSerializerSettings serializerSettings)
|
|
|
{
|
|
|
if (serializerSettings == null)
|
|
|
@@ -60,54 +57,34 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
|
|
throw new ArgumentNullException(nameof(serializerSettings));
|
|
|
}
|
|
|
|
|
|
- var jsonOutputFormatter = new NewtonsoftJsonOutputFormatter(serializerSettings, _charPool);
|
|
|
-
|
|
|
- return SerializeInternal(jsonOutputFormatter, value);
|
|
|
+ var jsonSerializer = CreateHtmlSafeSerializer(serializerSettings);
|
|
|
+ return Serialize(value, jsonSerializer);
|
|
|
}
|
|
|
|
|
|
- private IHtmlContent SerializeInternal(NewtonsoftJsonOutputFormatter jsonOutputFormatter, object value)
|
|
|
+ private IHtmlContent Serialize(object value, JsonSerializer jsonSerializer)
|
|
|
{
|
|
|
- var stringWriter = new StringWriter(CultureInfo.InvariantCulture);
|
|
|
- jsonOutputFormatter.WriteObject(stringWriter, value);
|
|
|
+ using (var stringWriter = new StringWriter(CultureInfo.InvariantCulture))
|
|
|
+ {
|
|
|
+ var jsonWriter = new JsonTextWriter(stringWriter)
|
|
|
+ {
|
|
|
+ ArrayPool = _charPool,
|
|
|
+ };
|
|
|
|
|
|
- return new HtmlString(stringWriter.ToString());
|
|
|
+ using (jsonWriter)
|
|
|
+ {
|
|
|
+ jsonSerializer.Serialize(jsonWriter, value);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new HtmlString(stringWriter.ToString());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private static JsonSerializerSettings ShallowCopy(JsonSerializerSettings settings)
|
|
|
+ private static JsonSerializer CreateHtmlSafeSerializer(JsonSerializerSettings serializerSettings)
|
|
|
{
|
|
|
- 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,
|
|
|
- };
|
|
|
-
|
|
|
- return copiedSettings;
|
|
|
+ var jsonSerializer = JsonSerializer.Create(serializerSettings);
|
|
|
+ // Ignore the user configured StringEscapeHandling and always escape it.
|
|
|
+ jsonSerializer.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
|
|
|
+ return jsonSerializer;
|
|
|
}
|
|
|
}
|
|
|
}
|