diff --git a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs index 2972cd648..fff4b75e7 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -179,7 +179,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent foreach (var item in array) { - if (item is JsonNull n) + if (item is JsonNull) { result.Add(null); } diff --git a/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs b/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs index ffd7d333a..29dab6b57 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsByNameIndexGrain.cs @@ -40,11 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes public Task ReserveAppAsync(Guid appId, string name) { - var canReserve = - !State.Apps.ContainsKey(name) && - !State.Apps.Any(x => x.Value == appId) && - !reservedIds.Contains(appId) && - !reservedNames.Contains(name); + var canReserve = !IsInUse(appId, name) && !IsReserved(appId, name); if (canReserve) { @@ -55,6 +51,16 @@ namespace Squidex.Domain.Apps.Entities.Apps.Indexes return Task.FromResult(canReserve); } + private bool IsInUse(Guid appId, string name) + { + return State.Apps.ContainsKey(name) || State.Apps.All(x => x.Value == appId); + } + + private bool IsReserved(Guid appId, string name) + { + return reservedIds.Contains(appId) || reservedNames.Contains(name); + } + public Task RemoveReservationAsync(Guid appId, string name) { reservedIds.Remove(appId); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs index d1885adcd..051f66a7a 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs @@ -22,15 +22,15 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentSchedulerGrain : Grain, IContentSchedulerGrain, IRemindable { - private readonly Lazy contentRepository; - private readonly Lazy commandBus; + private readonly IContentRepository contentRepository; + private readonly ICommandBus commandBus; private readonly IClock clock; private readonly ISemanticLog log; private TaskScheduler scheduler; public ContentSchedulerGrain( - Lazy contentRepository, - Lazy commandBus, + IContentRepository contentRepository, + ICommandBus commandBus, IClock clock, ISemanticLog log) { @@ -39,9 +39,11 @@ namespace Squidex.Domain.Apps.Entities.Contents Guard.NotNull(clock, nameof(clock)); Guard.NotNull(log, nameof(log)); - this.contentRepository = contentRepository; - this.commandBus = commandBus; this.clock = clock; + + this.commandBus = commandBus; + this.contentRepository = contentRepository; + this.log = log; } @@ -66,7 +68,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var now = clock.GetCurrentInstant(); - return contentRepository.Value.QueryScheduledWithoutDataAsync(now, content => + return contentRepository.QueryScheduledWithoutDataAsync(now, content => { return Dispatch(async () => { @@ -78,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents { var command = new ChangeContentStatus { ContentId = content.Id, Status = job.Status, Actor = job.ScheduledBy, JobId = job.Id }; - await commandBus.Value.PublishAsync(command); + await commandBus.PublishAsync(command); } } catch (Exception ex) diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs index 77019a716..7fe870e3c 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs @@ -8,6 +8,7 @@ using System; using System.Linq; using System.Reflection; +using System.Threading; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using Newtonsoft.Json; @@ -17,36 +18,41 @@ namespace Squidex.Infrastructure.MongoDb { public static class BsonJsonConvention { + private static volatile int isRegistered; + public static void Register(JsonSerializer serializer) { - var pack = new ConventionPack(); - - pack.AddMemberMapConvention("JsonBson", memberMap => + if (Interlocked.Increment(ref isRegistered) == 1) { - var attributes = memberMap.MemberInfo.GetCustomAttributes(); + var pack = new ConventionPack(); - if (attributes.OfType().Any()) + pack.AddMemberMapConvention("JsonBson", memberMap => { - var bsonSerializerType = typeof(BsonJsonSerializer<>).MakeGenericType(memberMap.MemberType); - var bsonSerializer = Activator.CreateInstance(bsonSerializerType, serializer); + var attributes = memberMap.MemberInfo.GetCustomAttributes(); - memberMap.SetSerializer((IBsonSerializer)bsonSerializer); - } - else if (memberMap.MemberType == typeof(JToken)) - { - memberMap.SetSerializer(JTokenSerializer.Instance); - } - else if (memberMap.MemberType == typeof(JObject)) - { - memberMap.SetSerializer(JTokenSerializer.Instance); - } - else if (memberMap.MemberType == typeof(JValue)) - { - memberMap.SetSerializer(JTokenSerializer.Instance); - } - }); + if (attributes.OfType().Any()) + { + var bsonSerializerType = typeof(BsonJsonSerializer<>).MakeGenericType(memberMap.MemberType); + var bsonSerializer = Activator.CreateInstance(bsonSerializerType, serializer); + + memberMap.SetSerializer((IBsonSerializer)bsonSerializer); + } + else if (memberMap.MemberType == typeof(JToken)) + { + memberMap.SetSerializer(JTokenSerializer.Instance); + } + else if (memberMap.MemberType == typeof(JObject)) + { + memberMap.SetSerializer(JTokenSerializer.Instance); + } + else if (memberMap.MemberType == typeof(JValue)) + { + memberMap.SetSerializer(JTokenSerializer.Instance); + } + }); - ConventionRegistry.Register("json", pack, t => true); + ConventionRegistry.Register("json", pack, t => true); + } } } } \ No newline at end of file diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs index b4a5d5926..6979cafe3 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/InstantSerializer.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using System.Threading; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using NodaTime; @@ -14,16 +14,14 @@ namespace Squidex.Infrastructure.MongoDb { public sealed class InstantSerializer : SerializerBase, IBsonPolymorphicSerializer { - private static readonly Lazy Registerer = new Lazy(() => - { - BsonSerializer.RegisterSerializer(new InstantSerializer()); - - return true; - }); + private static volatile int isRegistered; - public static bool Register() + public static void Register() { - return !Registerer.IsValueCreated && Registerer.Value; + if (Interlocked.Increment(ref isRegistered) == 1) + { + BsonSerializer.RegisterSerializer(new InstantSerializer()); + } } public bool IsDiscriminatorCompatibleWithObjectSerializer diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs index 00237ee83..689bdfe8e 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs @@ -44,6 +44,7 @@ namespace Squidex.Infrastructure.MongoDb static MongoRepositoryBase() { RefTokenSerializer.Register(); + InstantSerializer.Register(); } diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs index 6f8761148..b4c45f945 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/RefTokenSerializer.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; +using System.Threading; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; @@ -13,16 +13,14 @@ namespace Squidex.Infrastructure.MongoDb { public class RefTokenSerializer : ClassSerializerBase { - private static readonly Lazy Registerer = new Lazy(() => - { - BsonSerializer.RegisterSerializer(new RefTokenSerializer()); - - return true; - }); + private static volatile int isRegistered; - public static bool Register() + public static void Register() { - return !Registerer.IsValueCreated && Registerer.Value; + if (Interlocked.Increment(ref isRegistered) == 1) + { + BsonSerializer.RegisterSerializer(new RefTokenSerializer()); + } } protected override RefToken DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) diff --git a/src/Squidex.Infrastructure.Redis/RedisPubSub.cs b/src/Squidex.Infrastructure.Redis/RedisPubSub.cs index 3feaf1510..74ef5c100 100644 --- a/src/Squidex.Infrastructure.Redis/RedisPubSub.cs +++ b/src/Squidex.Infrastructure.Redis/RedisPubSub.cs @@ -19,22 +19,19 @@ namespace Squidex.Infrastructure public sealed class RedisPubSub : IPubSub, IInitializable { private readonly ConcurrentDictionary subscriptions = new ConcurrentDictionary(); - private readonly Lazy redisClient; + private readonly IConnectionMultiplexer redis; private readonly IJsonSerializer serializer; - private readonly Lazy redisSubscriber; private readonly ISemanticLog log; + private ISubscriber redisSubscriber; - public RedisPubSub(Lazy redis, IJsonSerializer serializer, ISemanticLog log) + public RedisPubSub(IConnectionMultiplexer redis, IJsonSerializer serializer, ISemanticLog log) { Guard.NotNull(serializer, nameof(serializer)); Guard.NotNull(redis, nameof(redis)); Guard.NotNull(log, nameof(log)); this.log = log; - - redisClient = redis; - redisSubscriber = new Lazy(() => redis.Value.GetSubscriber()); - + this.redis = redis; this.serializer = serializer; } @@ -42,13 +39,15 @@ namespace Squidex.Infrastructure { try { - redisClient.Value.GetStatus(); + redisSubscriber = redis.GetSubscriber(); + + redis.GetStatus(); return TaskHelper.Done; } catch (Exception ex) { - throw new ConfigurationException($"Redis connection failed to connect to database {redisClient.Value.Configuration}", ex); + throw new ConfigurationException($"Redis connection failed to connect to database {redis.Configuration}", ex); } } @@ -66,7 +65,7 @@ namespace Squidex.Infrastructure { var typeName = typeof(T).FullName; - return (RedisSubscription)subscriptions.GetOrAdd(typeName, this, (k, c) => new RedisSubscription(c.redisSubscriber.Value, serializer, k, c.log)); + return (RedisSubscription)subscriptions.GetOrAdd(typeName, this, (k, c) => new RedisSubscription(c.redisSubscriber, serializer, k, c.log)); } } } diff --git a/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs b/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs index 82c4e2dc9..f36089eeb 100644 --- a/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs +++ b/src/Squidex.Infrastructure/Assets/ImageSharp/ImageSharpAssetThumbnailGenerator.cs @@ -19,8 +19,8 @@ namespace Squidex.Infrastructure.Assets.ImageSharp { public ImageSharpAssetThumbnailGenerator() { - SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.AddImageFormat(ImageFormats.Jpeg); - SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.AddImageFormat(ImageFormats.Png); + Configuration.Default.ImageFormatsManager.AddImageFormat(ImageFormats.Jpeg); + Configuration.Default.ImageFormatsManager.AddImageFormat(ImageFormats.Png); } public Task CreateThumbnailAsync(Stream source, Stream destination, int? width, int? height, string mode) diff --git a/src/Squidex.Infrastructure/DependencyInjection/DependencyInjectionExtensions.cs b/src/Squidex.Infrastructure/DependencyInjection/DependencyInjectionExtensions.cs index da40d75eb..13f245759 100644 --- a/src/Squidex.Infrastructure/DependencyInjection/DependencyInjectionExtensions.cs +++ b/src/Squidex.Infrastructure/DependencyInjection/DependencyInjectionExtensions.cs @@ -72,15 +72,6 @@ namespace Microsoft.Extensions.DependencyInjection return new InterfaceRegistrator(services); } - public static InterfaceRegistrator AddSingletonAs(this IServiceCollection services, T instance) where T : class - { - services.AddSingleton(typeof(T), instance); - - RegisterDefaults(services); - - return new InterfaceRegistrator(services); - } - public static InterfaceRegistrator AddSingletonAs(this IServiceCollection services) where T : class { services.AddSingleton(); diff --git a/src/Squidex.Infrastructure/Lazier.cs b/src/Squidex.Infrastructure/Lazier.cs deleted file mode 100644 index aae97240c..000000000 --- a/src/Squidex.Infrastructure/Lazier.cs +++ /dev/null @@ -1,20 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschraenkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Squidex.Infrastructure -{ - public sealed class Lazier : Lazy where T : class - { - public Lazier(IServiceProvider provider) - : base(provider.GetRequiredService) - { - } - } -} diff --git a/src/Squidex.Infrastructure/Singletons.cs b/src/Squidex.Infrastructure/Singletons.cs index 494157155..e0eb715ab 100644 --- a/src/Squidex.Infrastructure/Singletons.cs +++ b/src/Squidex.Infrastructure/Singletons.cs @@ -18,10 +18,5 @@ namespace Squidex.Infrastructure { return Instances.GetOrAdd(key, factory); } - - public static Lazy GetOrAddLazy(string key, Func factory) - { - return new Lazy(() => Instances.GetOrAdd(key, factory)); - } } } diff --git a/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs b/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs index 09920e6b6..5409faca1 100644 --- a/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs +++ b/src/Squidex.Infrastructure/Translations/DeepLTranslator.cs @@ -87,7 +87,7 @@ namespace Squidex.Infrastructure.Translations return new Translation(TranslationResult.Failed, resultText: responseString); } - private string GetLanguageCode(Language language) + private static string GetLanguageCode(Language language) { return language.Iso2Code.Substring(0, 2).ToUpperInvariant(); } diff --git a/src/Squidex/Config/Domain/InfrastructureServices.cs b/src/Squidex/Config/Domain/InfrastructureServices.cs index 8e1b2e042..7b2e5d335 100644 --- a/src/Squidex/Config/Domain/InfrastructureServices.cs +++ b/src/Squidex/Config/Domain/InfrastructureServices.cs @@ -36,7 +36,12 @@ namespace Squidex.Config.Domain .AddCheck("Orleans", tags: new[] { "cluster" }) .AddCheck("Orleans App", tags: new[] { "cluster" }); - services.AddSingletonAs(SystemClock.Instance) + services.AddSingletonAs(c => new CachingUsageTracker( + c.GetRequiredService(), + c.GetRequiredService())) + .As(); + + services.AddSingletonAs(_ => SystemClock.Instance) .As(); services.AddSingletonAs() @@ -48,9 +53,6 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); - services.AddSingletonAs(c => new CachingUsageTracker(c.GetRequiredService(), c.GetRequiredService())) - .As(); - services.AddSingletonAs() .As(); @@ -68,8 +70,6 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); - - services.AddTransient(typeof(Lazy<>), typeof(Lazier<>)); } } } diff --git a/src/Squidex/Config/Domain/LoggingServices.cs b/src/Squidex/Config/Domain/LoggingServices.cs index 59e7932e3..60c4d6333 100644 --- a/src/Squidex/Config/Domain/LoggingServices.cs +++ b/src/Squidex/Config/Domain/LoggingServices.cs @@ -20,12 +20,12 @@ namespace Squidex.Config.Domain { if (config.GetValue("logging:human")) { - services.AddSingletonAs(JsonLogWriterFactory.Readable()) + services.AddSingletonAs(_ => JsonLogWriterFactory.Readable()) .As(); } else { - services.AddSingletonAs(JsonLogWriterFactory.Default()) + services.AddSingletonAs(_ => JsonLogWriterFactory.Default()) .As(); } @@ -33,16 +33,16 @@ namespace Squidex.Config.Domain if (!string.IsNullOrWhiteSpace(loggingFile)) { - services.AddSingletonAs(new FileChannel(loggingFile)) + services.AddSingletonAs(_ => new FileChannel(loggingFile)) .As(); } var useColors = config.GetValue("logging:colors"); - services.AddSingletonAs(new ConsoleLogChannel(useColors)) + services.AddSingletonAs(_ => new ConsoleLogChannel(useColors)) .As(); - services.AddSingletonAs(c => new ApplicationInfoLogAppender(typeof(Program).Assembly, Guid.NewGuid())) + services.AddSingletonAs(_ => new ApplicationInfoLogAppender(typeof(Program).Assembly, Guid.NewGuid())) .As(); services.AddSingletonAs() diff --git a/src/Squidex/Config/Domain/StoreServices.cs b/src/Squidex/Config/Domain/StoreServices.cs index a980bafc6..63559f3d4 100644 --- a/src/Squidex/Config/Domain/StoreServices.cs +++ b/src/Squidex/Config/Domain/StoreServices.cs @@ -50,7 +50,7 @@ namespace Squidex.Config.Domain services.AddSingleton(typeof(ISnapshotStore<,>), typeof(MongoSnapshotStore<,>)); - services.AddSingletonAs(c => Singletons.GetOrAdd(mongoConfiguration, s => new MongoClient(s))) + services.AddSingletonAs(_ => Singletons.GetOrAdd(mongoConfiguration, s => new MongoClient(s))) .As(); services.AddSingletonAs(c => c.GetRequiredService().GetDatabase(mongoDatabaseName)) diff --git a/src/Squidex/Pipeline/Plugins/PluginExtensions.cs b/src/Squidex/Pipeline/Plugins/PluginExtensions.cs index 507d285af..0ba06a608 100644 --- a/src/Squidex/Pipeline/Plugins/PluginExtensions.cs +++ b/src/Squidex/Pipeline/Plugins/PluginExtensions.cs @@ -83,8 +83,6 @@ namespace Squidex.Pipeline.Plugins private static PluginLoader LoadPlugin(string pluginPath) { - var fullPath = GetPaths(pluginPath); - foreach (var candidate in GetPaths(pluginPath)) { if (candidate.Extension.Equals(".dll", StringComparison.OrdinalIgnoreCase))