From ac1ccac34cd53909805a18df46e3b23b60cf643c Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sat, 1 Dec 2018 12:59:54 +0100 Subject: [PATCH] More optimizations. --- .../MongoDb/BsonJsonReader.cs | 20 +++++----- .../MongoDb/MongoExtensions.cs | 5 +-- .../Newtonsoft/ConverterContractResolver.cs | 39 +++++++++++++++++-- .../Newtonsoft/EnvelopeHeadersConverter.cs | 6 +++ .../Json/Newtonsoft/ISupportedTypes.cs | 17 ++++++++ .../Json/Newtonsoft/InstantConverter.cs | 10 +++++ .../Json/Newtonsoft/JsonClassConverter.cs | 16 +++++--- .../Json/Newtonsoft/JsonValueConverter.cs | 21 +++++++++- .../Log/JsonLogWriter.cs | 28 ++++++++----- .../Config/Domain/SerializationServices.cs | 4 -- src/Squidex/Squidex.csproj | 1 - 11 files changed, 128 insertions(+), 39 deletions(-) create mode 100644 src/Squidex.Infrastructure/Json/Newtonsoft/ISupportedTypes.cs diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs index acb8708fa..f801aeddc 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonReader.cs @@ -37,16 +37,6 @@ namespace Squidex.Infrastructure.MongoDb { SetToken(NewtonsoftJsonToken.PropertyName, bsonReader.ReadName().UnescapeBson()); } - else if (bsonReader.State == BsonReaderState.EndOfDocument) - { - SetToken(NewtonsoftJsonToken.EndObject); - bsonReader.ReadEndDocument(); - } - else if (bsonReader.State == BsonReaderState.EndOfArray) - { - SetToken(NewtonsoftJsonToken.EndArray); - bsonReader.ReadEndArray(); - } else if (bsonReader.State == BsonReaderState.Value) { switch (bsonReader.CurrentBsonType) @@ -95,6 +85,16 @@ namespace Squidex.Infrastructure.MongoDb throw new NotSupportedException(); } } + else if (bsonReader.State == BsonReaderState.EndOfDocument) + { + SetToken(NewtonsoftJsonToken.EndObject); + bsonReader.ReadEndDocument(); + } + else if (bsonReader.State == BsonReaderState.EndOfArray) + { + SetToken(NewtonsoftJsonToken.EndArray); + bsonReader.ReadEndArray(); + } if (bsonReader.State == BsonReaderState.Initial) { diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs index 3681a4aa7..d8baba185 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs @@ -101,10 +101,7 @@ namespace Squidex.Infrastructure.MongoDb { var update = updater(Builders.Update.Set(x => x.Version, newVersion)); - await collection.UpdateOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion, - update - .Set(x => x.Version, newVersion), - Upsert); + await collection.UpdateOneAsync(x => x.Id.Equals(key) && x.Version == oldVersion, update, Upsert); } catch (MongoWriteException ex) { diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs index e626d5e1d..53b203da3 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/ConverterContractResolver.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -14,10 +15,23 @@ namespace Squidex.Infrastructure.Json.Newtonsoft public sealed class ConverterContractResolver : CamelCasePropertyNamesContractResolver { private readonly JsonConverter[] converters; + private readonly object lockObject = new object(); + private Dictionary converterCache = new Dictionary(); public ConverterContractResolver(params JsonConverter[] converters) { this.converters = converters; + + foreach (var converter in converters) + { + if (converter is ISupportedTypes supportedTypes) + { + foreach (var type in supportedTypes.SupportedTypes) + { + converterCache[type] = converter; + } + } + } } protected override JsonDictionaryContract CreateDictionaryContract(Type objectType) @@ -38,15 +52,32 @@ namespace Squidex.Infrastructure.Json.Newtonsoft return result; } - foreach (var converter in converters) + var cache = converterCache; + + if (cache == null || !cache.TryGetValue(objectType, out result)) { - if (converter.CanConvert(objectType)) + foreach (var converter in converters) + { + if (converter.CanConvert(objectType)) + { + result = converter; + } + } + + lock (lockObject) { - return converter; + cache = converterCache; + + var updatedCache = (cache != null) + ? new Dictionary(cache) + : new Dictionary(); + updatedCache[objectType] = result; + + converterCache = updatedCache; } } - return null; + return result; } } } diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/EnvelopeHeadersConverter.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/EnvelopeHeadersConverter.cs index a90b97950..d4a529395 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/EnvelopeHeadersConverter.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/EnvelopeHeadersConverter.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using Newtonsoft.Json; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Json.Objects; @@ -14,6 +15,11 @@ namespace Squidex.Infrastructure.Json.Newtonsoft { public sealed class EnvelopeHeadersConverter : JsonValueConverter { + public override IEnumerable SupportedTypes + { + get { yield return typeof(EnvelopeHeaders); } + } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var result = base.ReadJson(reader, objectType, existingValue, serializer); diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/ISupportedTypes.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/ISupportedTypes.cs new file mode 100644 index 000000000..fa28fb93c --- /dev/null +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/ISupportedTypes.cs @@ -0,0 +1,17 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; + +namespace Squidex.Infrastructure.Json.Newtonsoft +{ + public interface ISupportedTypes + { + IEnumerable SupportedTypes { get; } + } +} diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/InstantConverter.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/InstantConverter.cs index 463d24411..9663accf9 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/InstantConverter.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/InstantConverter.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using Newtonsoft.Json; using NodaTime; using NodaTime.Text; @@ -14,6 +15,15 @@ namespace Squidex.Infrastructure.Json.Newtonsoft { public sealed class InstantConverter : JsonConverter { + public IEnumerable SupportedTypes + { + get + { + yield return typeof(Instant); + yield return typeof(Instant?); + } + } + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value != null) diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/JsonClassConverter.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/JsonClassConverter.cs index 078bd451e..03acfc2f5 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/JsonClassConverter.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/JsonClassConverter.cs @@ -6,12 +6,18 @@ // ========================================================================== using System; +using System.Collections.Generic; using Newtonsoft.Json; namespace Squidex.Infrastructure.Json.Newtonsoft { - public abstract class JsonClassConverter : JsonConverter where T : class + public abstract class JsonClassConverter : JsonConverter, ISupportedTypes where T : class { + public IEnumerable SupportedTypes + { + get { yield return typeof(T); } + } + public sealed override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) @@ -22,6 +28,8 @@ namespace Squidex.Infrastructure.Json.Newtonsoft return ReadValue(reader, objectType, serializer); } + protected abstract T ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer); + public sealed override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (value == null) @@ -33,13 +41,11 @@ namespace Squidex.Infrastructure.Json.Newtonsoft WriteValue(writer, (T)value, serializer); } + protected abstract void WriteValue(JsonWriter writer, T value, JsonSerializer serializer); + public override bool CanConvert(Type objectType) { return objectType == typeof(T); } - - protected abstract void WriteValue(JsonWriter writer, T value, JsonSerializer serializer); - - protected abstract T ReadValue(JsonReader reader, Type objectType, JsonSerializer serializer); } } diff --git a/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs b/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs index 917099317..0e4282826 100644 --- a/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs +++ b/src/Squidex.Infrastructure/Json/Newtonsoft/JsonValueConverter.cs @@ -6,6 +6,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json; using Squidex.Infrastructure.Json.Objects; @@ -14,8 +15,24 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Infrastructure.Json.Newtonsoft { - public class JsonValueConverter : JsonConverter + public class JsonValueConverter : JsonConverter, ISupportedTypes { + private readonly HashSet supportedTypes = new HashSet + { + typeof(IJsonValue), + typeof(JsonArray), + typeof(JsonBoolean), + typeof(JsonNull), + typeof(JsonNumber), + typeof(JsonObject), + typeof(JsonString) + }; + + public virtual IEnumerable SupportedTypes + { + get { return supportedTypes; } + } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return ReadJson(reader); @@ -161,7 +178,7 @@ namespace Squidex.Infrastructure.Json.Newtonsoft public override bool CanConvert(Type objectType) { - return typeof(IJsonValue).IsAssignableFrom(objectType); + return supportedTypes.Contains(objectType); } } } diff --git a/src/Squidex.Infrastructure/Log/JsonLogWriter.cs b/src/Squidex.Infrastructure/Log/JsonLogWriter.cs index 4d8012f8f..b90cf64eb 100644 --- a/src/Squidex.Infrastructure/Log/JsonLogWriter.cs +++ b/src/Squidex.Infrastructure/Log/JsonLogWriter.cs @@ -96,7 +96,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, string value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value); return this; @@ -104,7 +104,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, double value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value); return this; @@ -112,7 +112,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, long value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value); return this; @@ -120,7 +120,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, bool value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value); return this; @@ -128,7 +128,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, DateTime value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value.ToString("o", CultureInfo.InvariantCulture)); return this; @@ -136,7 +136,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, DateTimeOffset value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value.ToString("o", CultureInfo.InvariantCulture)); return this; @@ -144,7 +144,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteProperty(string property, TimeSpan value) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteValue(value); return this; @@ -152,7 +152,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteObject(string property, Action objectWriter) { - jsonWriter.WritePropertyName(property); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteStartObject(); objectWriter?.Invoke(this); @@ -164,7 +164,7 @@ namespace Squidex.Infrastructure.Log IObjectWriter IObjectWriter.WriteArray(string property, Action arrayWriter) { - jsonWriter.WritePropertyName(property.ToCamelCase()); + jsonWriter.WritePropertyName(Format(property)); jsonWriter.WriteStartArray(); arrayWriter?.Invoke(this); @@ -185,6 +185,16 @@ namespace Squidex.Infrastructure.Log return this; } + private static string Format(string property) + { + if (ReferenceEquals(string.IsInterned(property), property)) + { + return property; + } + + return property.ToCamelCase(); + } + public override string ToString() { jsonWriter.WriteEndObject(); diff --git a/src/Squidex/Config/Domain/SerializationServices.cs b/src/Squidex/Config/Domain/SerializationServices.cs index 500a1aad3..87916c8ac 100644 --- a/src/Squidex/Config/Domain/SerializationServices.cs +++ b/src/Squidex/Config/Domain/SerializationServices.cs @@ -9,8 +9,6 @@ using Microsoft.Extensions.DependencyInjection; using Migrate_01; using Newtonsoft.Json; using Newtonsoft.Json.Converters; -using NodaTime; -using NodaTime.Serialization.JsonNet; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps.Json; using Squidex.Domain.Apps.Core.Rules.Json; @@ -68,8 +66,6 @@ namespace Squidex.Config.Domain settings.DateParseHandling = DateParseHandling.None; settings.TypeNameHandling = typeNameHandling; - - settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); } static SerializationServices() diff --git a/src/Squidex/Squidex.csproj b/src/Squidex/Squidex.csproj index 93f9dad74..478449461 100644 --- a/src/Squidex/Squidex.csproj +++ b/src/Squidex/Squidex.csproj @@ -80,7 +80,6 @@ -