diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
index 8926174c03..29e501f993 100644
--- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
+++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs
@@ -25,6 +25,12 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType)
=> PropertyCacheLevel.Element;
+ private static readonly JsonSerializerSettings ImageCropperValueJsonSerializerSettings = new JsonSerializerSettings
+ {
+ Culture = CultureInfo.InvariantCulture,
+ FloatParseHandling = FloatParseHandling.Decimal
+ };
+
///
public override object ConvertSourceToIntermediate(IPublishedElement owner, IPublishedPropertyType propertyType, object source, bool preview)
{
@@ -34,11 +40,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
ImageCropperValue value;
try
{
- value = JsonConvert.DeserializeObject(sourceString, new JsonSerializerSettings
- {
- Culture = CultureInfo.InvariantCulture,
- FloatParseHandling = FloatParseHandling.Decimal
- });
+ value = JsonConvert.DeserializeObject(sourceString, ImageCropperValueJsonSerializerSettings);
}
catch (Exception ex)
{
diff --git a/src/Umbraco.Core/Serialization/NoTypeConverterJsonConverter.cs b/src/Umbraco.Core/Serialization/NoTypeConverterJsonConverter.cs
index b06ee870de..ab64d5b368 100644
--- a/src/Umbraco.Core/Serialization/NoTypeConverterJsonConverter.cs
+++ b/src/Umbraco.Core/Serialization/NoTypeConverterJsonConverter.cs
@@ -19,6 +19,7 @@ namespace Umbraco.Core.Serialization
internal class NoTypeConverterJsonConverter : JsonConverter
{
static readonly IContractResolver resolver = new NoTypeConverterContractResolver();
+ private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings { ContractResolver = resolver };
private class NoTypeConverterContractResolver : DefaultContractResolver
{
@@ -41,12 +42,12 @@ namespace Umbraco.Core.Serialization
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
- return JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Deserialize(reader, objectType);
+ return JsonSerializer.CreateDefault(JsonSerializerSettings).Deserialize(reader, objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
- JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Serialize(writer, value);
+ JsonSerializer.CreateDefault(JsonSerializerSettings).Serialize(writer, value);
}
}
}
diff --git a/src/Umbraco.Tests.Benchmarks/JsonSerializerSettingsBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/JsonSerializerSettingsBenchmarks.cs
new file mode 100644
index 0000000000..7f419547bd
--- /dev/null
+++ b/src/Umbraco.Tests.Benchmarks/JsonSerializerSettingsBenchmarks.cs
@@ -0,0 +1,69 @@
+using BenchmarkDotNet.Attributes;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Umbraco.Tests.Benchmarks.Config;
+
+namespace Umbraco.Tests.Benchmarks
+{
+ [QuickRunConfig]
+ [MemoryDiagnoser]
+ public class JsonSerializerSettingsBenchmarks
+ {
+ [Benchmark]
+ public void SerializerSettingsInstantiation()
+ {
+ int instances = 1000;
+ for (int i = 0; i < instances; i++)
+ {
+ new JsonSerializerSettings();
+ }
+ }
+
+ [Benchmark(Baseline =true)]
+ public void SerializerSettingsSingleInstantiation()
+ {
+ new JsonSerializerSettings();
+ }
+
+// // * Summary *
+
+// BenchmarkDotNet=v0.11.3, OS=Windows 10.0.18362
+//Intel Core i5-8265U CPU 1.60GHz(Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
+// [Host] : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.8.4250.0
+// Job-JIATTD : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.8.4250.0
+
+//IterationCount=3 IterationTime=100.0000 ms LaunchCount = 1
+//WarmupCount=3
+
+// Method | Mean | Error | StdDev | Ratio | RatioSD | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
+//-------------------------------------- |-------------:|-------------:|------------:|-------:|--------:|------------:|------------:|------------:|--------------------:|
+// SerializerSettingsInstantiation | 29,120.48 ns | 5,532.424 ns | 303.2508 ns | 997.84 | 23.66 | 73.8122 | - | - | 232346 B |
+// SerializerSettingsSingleInstantiation | 29.19 ns | 8.089 ns | 0.4434 ns | 1.00 | 0.00 | 0.0738 | - | - | 232 B |
+
+//// * Warnings *
+//MinIterationTime
+// JsonSerializerSettingsBenchmarks.SerializerSettingsSingleInstantiation: IterationCount= 3, IterationTime= 100.0000 ms, LaunchCount= 1, WarmupCount= 3->MinIterationTime = 96.2493 ms which is very small. It's recommended to increase it.
+
+//// * Legends *
+// Mean : Arithmetic mean of all measurements
+// Error : Half of 99.9% confidence interval
+// StdDev : Standard deviation of all measurements
+// Ratio : Mean of the ratio distribution ([Current]/[Baseline])
+// RatioSD : Standard deviation of the ratio distribution([Current]/[Baseline])
+// Gen 0/1k Op : GC Generation 0 collects per 1k Operations
+// Gen 1/1k Op : GC Generation 1 collects per 1k Operations
+// Gen 2/1k Op : GC Generation 2 collects per 1k Operations
+// Allocated Memory/Op : Allocated memory per single operation(managed only, inclusive, 1KB = 1024B)
+// 1 ns : 1 Nanosecond(0.000000001 sec)
+
+//// * Diagnostic Output - MemoryDiagnoser *
+
+
+// // ***** BenchmarkRunner: End *****
+// Run time: 00:00:04 (4.88 sec), executed benchmarks: 2
+ }
+}
diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
index 48d69cf757..58b45aa743 100644
--- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
+++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj
@@ -53,6 +53,7 @@
+
diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs
index 458c76b3ae..92b67cbf1b 100644
--- a/src/Umbraco.Web/Editors/BackOfficeController.cs
+++ b/src/Umbraco.Web/Editors/BackOfficeController.cs
@@ -226,7 +226,7 @@ namespace Umbraco.Web.Editors
.ToDictionary(pv => pv.Key, pv =>
pv.ToDictionary(pve => pve.valueAlias, pve => pve.value));
- return new JsonNetResult { Data = nestedDictionary, Formatting = Formatting.None };
+ return new JsonNetResult(JsonNetResult.DefaultJsonSerializerSettings) { Data = nestedDictionary, Formatting = Formatting.None };
}
///
@@ -273,7 +273,7 @@ namespace Umbraco.Web.Editors
GetAssetList,
new TimeSpan(0, 2, 0));
- return new JsonNetResult { Data = result, Formatting = Formatting.None };
+ return new JsonNetResult(JsonNetResult.DefaultJsonSerializerSettings) { Data = result, Formatting = Formatting.None };
}
[UmbracoAuthorize(Order = 0)]
@@ -281,7 +281,7 @@ namespace Umbraco.Web.Editors
public JsonNetResult GetGridConfig()
{
var gridConfig = Current.Configs.Grids();
- return new JsonNetResult { Data = gridConfig.EditorsConfig.Editors, Formatting = Formatting.None };
+ return new JsonNetResult(JsonNetResult.DefaultJsonSerializerSettings) { Data = gridConfig.EditorsConfig.Editors, Formatting = Formatting.None };
}
diff --git a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
index 26dd2a5d36..78b55a8930 100644
--- a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
+++ b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs
@@ -253,19 +253,20 @@ namespace Umbraco.Web
ImageCropRatioMode? ratioMode = null,
bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(imageUrl, Current.ImageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
+ private static readonly JsonSerializerSettings ImageCropperValueJsonSerializerSettings = new JsonSerializerSettings
+ {
+ Culture = CultureInfo.InvariantCulture,
+ FloatParseHandling = FloatParseHandling.Decimal
+ };
internal static ImageCropperValue DeserializeImageCropperValue(this string json)
{
- var imageCrops = new ImageCropperValue();
+ ImageCropperValue imageCrops = null;
if (json.DetectIsJson())
{
try
{
- imageCrops = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
- {
- Culture = CultureInfo.InvariantCulture,
- FloatParseHandling = FloatParseHandling.Decimal
- });
+ imageCrops = JsonConvert.DeserializeObject(json, ImageCropperValueJsonSerializerSettings);
}
catch (Exception ex)
{
@@ -273,6 +274,7 @@ namespace Umbraco.Web
}
}
+ imageCrops = imageCrops ?? new ImageCropperValue();
return imageCrops;
}
}
diff --git a/src/Umbraco.Web/Mvc/JsonNetResult.cs b/src/Umbraco.Web/Mvc/JsonNetResult.cs
index da6780451e..3dd6c2f398 100644
--- a/src/Umbraco.Web/Mvc/JsonNetResult.cs
+++ b/src/Umbraco.Web/Mvc/JsonNetResult.cs
@@ -22,10 +22,19 @@ namespace Umbraco.Web.Mvc
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
+ ///
+ /// Default, unchanged JsonSerializerSettings
+ ///
+ public static readonly JsonSerializerSettings DefaultJsonSerializerSettings = new JsonSerializerSettings();
+
public JsonNetResult()
{
SerializerSettings = new JsonSerializerSettings();
}
+ public JsonNetResult(JsonSerializerSettings jsonSerializerSettings)
+ {
+ SerializerSettings = jsonSerializerSettings;
+ }
public override void ExecuteResult(ControllerContext context)
{
diff --git a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs
index 5a84e4b20c..560275b29a 100644
--- a/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs
+++ b/src/Umbraco.Web/PropertyEditors/MultiUrlPickerValueEditor.cs
@@ -121,6 +121,10 @@ namespace Umbraco.Web.PropertyEditors
return base.ToEditor(property, dataTypeService, culture, segment);
}
+ private static readonly JsonSerializerSettings LinkDisplayJsonSerializerSettings = new JsonSerializerSettings
+ {
+ NullValueHandling = NullValueHandling.Ignore
+ };
public override object FromEditor(ContentPropertyData editorValue, object currentValue)
{
@@ -142,11 +146,8 @@ namespace Umbraco.Web.PropertyEditors
Target = link.Target,
Udi = link.Udi,
Url = link.Udi == null ? link.Url : null, // only save the URL for external links
- },
- new JsonSerializerSettings
- {
- NullValueHandling = NullValueHandling.Ignore
- });
+ }, LinkDisplayJsonSerializerSettings
+ );
}
catch (Exception ex)
{
diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
index f62014a368..f9ad0ac715 100644
--- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
+++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs
@@ -303,17 +303,18 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return s;
}
+ private static readonly JsonSerializerSettings NestedContentDataJsonSerializerSettings = new JsonSerializerSettings
+ {
+ Converters = new List { new ForceInt32Converter() }
+ };
+
private static ContentNestedData DeserializeNestedData(string data)
{
// by default JsonConvert will deserialize our numeric values as Int64
// which is bad, because they were Int32 in the database - take care
- var settings = new JsonSerializerSettings
- {
- Converters = new List { new ForceInt32Converter() }
- };
- return JsonConvert.DeserializeObject(data, settings);
+ return JsonConvert.DeserializeObject(data, NestedContentDataJsonSerializerSettings);
}
}
}