From 765d3894c5781162e5ce55ff32b0471d85f5b8db Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 18 Oct 2017 20:26:38 +0200 Subject: [PATCH] Closes #145 Closes #144 --- .../Apps/MongoAppRepository_EventHandling.cs | 12 ----- .../Contents/Extensions.cs | 9 ++-- .../Contents/MongoContentEntity.cs | 5 ++- .../Contents/MongoContentRepository.cs | 14 +++--- .../MongoContentRepository_EventHandling.cs | 4 +- .../Schemas/MongoSchemaEntity.cs | 39 +++++++++------- .../Schemas/MongoSchemaRepository.cs | 12 ++++- .../MongoSchemaRepository_EventHandling.cs | 42 +++++++---------- .../Apps/IAppEntity.cs | 1 - .../Apps/Repositories/IAppRepository.cs | 3 -- .../Apps/Services/IAppProvider.cs | 3 -- .../Implementations/CachingAppProvider.cs | 45 +++++++++++++++---- .../Schemas/Repositories/ISchemaRepository.cs | 3 -- .../Schemas/Services/ISchemaProvider.cs | 3 -- .../Implementations/CachingSchemaProvider.cs | 45 +++++++++++++++---- .../CQRS/Events/RabbitMqEventConsumer.cs | 2 +- .../Config/Domain/InfrastructureModule.cs | 2 - src/Squidex/Config/Domain/Serializers.cs | 2 - .../Config/Domain/StoreMongoDbModule.cs | 22 ++++++++- src/Squidex/Config/Domain/Usages.cs | 20 --------- .../Config/Identity/LazyClientStore.cs | 1 - .../Apps/CachingAppProviderTests.cs | 28 ++++++++++-- .../Schemas/CachingSchemaProviderTests.cs | 26 +++++++++-- .../Json/ConverterContractResolverTests.cs | 2 +- 24 files changed, 210 insertions(+), 135 deletions(-) diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs index 74a2e9442..22166ec3f 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Apps/MongoAppRepository_EventHandling.cs @@ -22,8 +22,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps { public partial class MongoAppRepository { - private readonly List>> subscribers = new List>>(); - public string Name { get { return GetType().Name; } @@ -34,11 +32,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps get { return "^app-"; } } - public void SubscribeOnChanged(Action> subscriber) - { - subscribers.Add(subscriber); - } - public Task On(Envelope @event) { return this.DispatchActionAsync(@event.Payload, @event.Headers); @@ -144,11 +137,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Apps a.ContributorIds = a.Contributors.Keys.ToList(); }); - - foreach (var subscriber in subscribers) - { - subscriber(@event.AppId); - } } } } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs index 02245ae0c..9a5d1ee42 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/Extensions.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using MongoDB.Bson; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; @@ -22,9 +23,9 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents { private const int MaxLength = 1024 * 1024; - public static BsonDocument ToBsonDocument(this IdContentData data) + public static BsonDocument ToBsonDocument(this IdContentData data, JsonSerializer jsonSerializer) { - return (BsonDocument)JToken.FromObject(data).ToBson(); + return (BsonDocument)JToken.FromObject(data, jsonSerializer).ToBson(); } public static List ToReferencedIds(this IdContentData data, Schema schema) @@ -32,11 +33,11 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents return data.GetReferencedIds(schema).ToList(); } - public static NamedContentData ToData(this BsonDocument document, Schema schema, List deletedIds) + public static NamedContentData ToData(this BsonDocument document, Schema schema, List deletedIds, JsonSerializer jsonSerializer) { return document .ToJson() - .ToObject() + .ToObject(jsonSerializer) .ToCleanedReferences(schema, new HashSet(deletedIds ?? new List())) .ToNameModel(schema, true); } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs index 7a7be804b..5ca934612 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; @@ -82,9 +83,9 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents get { return data; } } - public void ParseData(Schema schema) + public void ParseData(Schema schema, JsonSerializer serializer) { - data = DataDocument.ToData(schema, ReferencedIdsDeleted); + data = DataDocument.ToData(schema, ReferencedIdsDeleted, serializer); } } } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs index 516e7de81..4f124278d 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs @@ -13,6 +13,7 @@ using System.Threading.Tasks; using Microsoft.OData.UriParser; using MongoDB.Bson; using MongoDB.Driver; +using Newtonsoft.Json; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Read.Apps; using Squidex.Domain.Apps.Read.Contents; @@ -30,6 +31,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents private const string Prefix = "Projections_Content_"; private readonly IMongoDatabase database; private readonly ISchemaProvider schemas; + private readonly JsonSerializer serializer; protected static FilterDefinitionBuilder Filter { @@ -63,13 +65,15 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents } } - public MongoContentRepository(IMongoDatabase database, ISchemaProvider schemas) + public MongoContentRepository(IMongoDatabase database, ISchemaProvider schemas, JsonSerializer serializer) { Guard.NotNull(database, nameof(database)); Guard.NotNull(schemas, nameof(schemas)); + Guard.NotNull(serializer, nameof(serializer)); - this.schemas = schemas; this.database = database; + this.schemas = schemas; + this.serializer = serializer; } public async Task> QueryAsync(IAppEntity app, ISchemaEntity schema, Status[] status, ODataUriParser odataQuery) @@ -99,7 +103,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents foreach (var entity in contentEntities) { - entity.ParseData(schema.SchemaDef); + entity.ParseData(schema.SchemaDef, serializer); } return contentEntities; @@ -147,7 +151,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents foreach (var entity in contentEntities) { - entity.ParseData(schema.SchemaDef); + entity.ParseData(schema.SchemaDef, serializer); } return contentEntities.OfType().ToList(); @@ -172,7 +176,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents await collection.Find(x => x.Id == id) .FirstOrDefaultAsync(); - contentEntity?.ParseData(schema.SchemaDef); + contentEntity?.ParseData(schema.SchemaDef, serializer); return contentEntity; } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs index 60921d90e..e6e122a46 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs @@ -79,7 +79,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents var idData = @event.Data?.ToIdModel(schema.SchemaDef, true); content.DataText = idData?.ToFullText(); - content.DataDocument = idData?.ToBsonDocument(); + content.DataDocument = idData?.ToBsonDocument(serializer); content.ReferencedIds = idData?.ToReferencedIds(schema.SchemaDef); }); }); @@ -95,7 +95,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents Filter.Eq(x => x.Id, @event.ContentId), Update .Set(x => x.DataText, idData.ToFullText()) - .Set(x => x.DataDocument, idData.ToBsonDocument()) + .Set(x => x.DataDocument, idData.ToBsonDocument(serializer)) .Set(x => x.ReferencedIds, idData.ToReferencedIds(schema.SchemaDef)) .Set(x => x.LastModified, headers.Timestamp()) .Set(x => x.LastModifiedBy, @event.Actor) diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs index f58dd7332..bedbbbbaa 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs @@ -9,6 +9,7 @@ using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Read.Schemas; @@ -19,7 +20,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas { public sealed class MongoSchemaEntity : MongoEntity, ISchemaEntity { - private Schema schema; + private Lazy schema; [BsonRequired] [BsonElement] @@ -73,23 +74,31 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas [BsonElement] public string ScriptChange { get; set; } - [BsonIgnore] - public Schema SchemaDef + Schema ISchemaEntity.SchemaDef { - get - { - if (schema == null) - { - schema = SchemaDocument.ToJson().ToObject(); - } + get { return schema.Value; } + } - return schema; - } - set - { - schema = value; + public void SerializeSchema(Schema newSchema, JsonSerializer serializer) + { + SchemaDocument = JObject.FromObject(newSchema, serializer).ToBson(); + schema = new Lazy(() => newSchema); + + IsPublished = newSchema.IsPublished; + } - SchemaDocument = (BsonDocument)JToken.FromObject(schema).ToBson(); + public void UpdateSchema(JsonSerializer serializer, Func updater) + { + DeserializeSchema(serializer); + + SerializeSchema(updater(schema.Value), serializer); + } + + public void DeserializeSchema(JsonSerializer serializer) + { + if (schema == null) + { + schema = new Lazy(() => schema != null ? SchemaDocument.ToJson().ToObject(serializer) : null); } } } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs index a43da664f..5e93dbcbc 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MongoDB.Driver; +using Newtonsoft.Json; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Read.Schemas; using Squidex.Domain.Apps.Read.Schemas.Repositories; @@ -22,14 +23,17 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas { public partial class MongoSchemaRepository : MongoRepositoryBase, ISchemaRepository, IEventConsumer { + private readonly JsonSerializer serializer; private readonly FieldRegistry registry; - public MongoSchemaRepository(IMongoDatabase database, FieldRegistry registry) + public MongoSchemaRepository(IMongoDatabase database, JsonSerializer serializer, FieldRegistry registry) : base(database) { Guard.NotNull(registry, nameof(registry)); + Guard.NotNull(serializer, nameof(serializer)); this.registry = registry; + this.serializer = serializer; } protected override string CollectionName() @@ -50,6 +54,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas await Collection.Find(s => s.AppId == appId && !s.IsDeleted) .ToListAsync(); + schemaEntities.ForEach(x => x.DeserializeSchema(serializer)); + return schemaEntities.OfType().ToList(); } @@ -59,6 +65,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas await Collection.Find(s => s.AppId == appId && !s.IsDeleted && s.Name == name) .FirstOrDefaultAsync(); + schemaEntity?.DeserializeSchema(serializer); + return schemaEntity; } @@ -68,6 +76,8 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas await Collection.Find(s => s.Id == schemaId) .FirstOrDefaultAsync(); + schemaEntity?.DeserializeSchema(serializer); + return schemaEntity; } } diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs index e057610b3..8499416d8 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs @@ -7,7 +7,6 @@ // ========================================================================== using System; -using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Events; @@ -15,7 +14,6 @@ using Squidex.Domain.Apps.Events.Schemas; using Squidex.Domain.Apps.Events.Schemas.Old; using Squidex.Domain.Apps.Events.Schemas.Utils; using Squidex.Domain.Apps.Read.MongoDb.Utils; -using Squidex.Infrastructure; using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.Dispatching; using Squidex.Infrastructure.Reflection; @@ -26,8 +24,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas { public partial class MongoSchemaRepository { - private readonly List, NamedId>> subscribers = new List, NamedId>>(); - public string Name { get { return GetType().Name; } @@ -38,11 +34,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas get { return "^schema-"; } } - public void SubscribeOnChanged(Action, NamedId> subscriber) - { - subscribers.Add(subscriber); - } - public Task On(Envelope @event) { return this.DispatchActionAsync(@event.Payload, @event.Headers); @@ -52,7 +43,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas { var schema = SchemaEventDispatcher.Dispatch(@event, registry); - return Collection.CreateAsync(@event, headers, s => { s.SchemaDef = schema; SimpleMapper.Map(@event, s); }); + return Collection.CreateAsync(@event, headers, s => { UpdateSchema(s, schema); SimpleMapper.Map(@event, s); }); } protected Task On(FieldDeleted @event, EnvelopeHeaders headers) @@ -125,30 +116,29 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas return Collection.UpdateAsync(@event, headers, e => e.IsDeleted = true); } - protected Task On(WebhookAdded @event, EnvelopeHeaders headers) + private Task UpdateSchema(SquidexEvent @event, EnvelopeHeaders headers, Func updater) { - return Collection.UpdateAsync(@event, headers, e => { }); + return Collection.UpdateAsync(@event, headers, e => UpdateSchema(e, updater)); } - protected Task On(WebhookDeleted @event, EnvelopeHeaders headers) + private void UpdateSchema(MongoSchemaEntity entity, Func updater) { - return Collection.UpdateAsync(@event, headers, e => { }); + entity.UpdateSchema(serializer, updater); } - private async Task UpdateSchema(SchemaEvent @event, EnvelopeHeaders headers, Func updater = null) + private void UpdateSchema(MongoSchemaEntity entity, Schema schema) { - await Collection.UpdateAsync(@event, headers, e => - { - if (updater != null) - { - e.SchemaDef = updater(e.SchemaDef); - } - }); + entity.SerializeSchema(schema, serializer); + } - foreach (var subscriber in subscribers) - { - subscriber(@event.AppId, @event.SchemaId); - } + protected Task On(WebhookAdded @event, EnvelopeHeaders headers) + { + return Collection.UpdateAsync(@event, headers, e => { }); + } + + protected Task On(WebhookDeleted @event, EnvelopeHeaders headers) + { + return Collection.UpdateAsync(@event, headers, e => { }); } } } diff --git a/src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs b/src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs index d9337d2f0..8c59f8628 100644 --- a/src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs +++ b/src/Squidex.Domain.Apps.Read/Apps/IAppEntity.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.Apps; namespace Squidex.Domain.Apps.Read.Apps { diff --git a/src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs b/src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs index c3b8113c0..67fef0148 100644 --- a/src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs +++ b/src/Squidex.Domain.Apps.Read/Apps/Repositories/IAppRepository.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Read.Apps.Repositories { @@ -20,7 +19,5 @@ namespace Squidex.Domain.Apps.Read.Apps.Repositories Task FindAppAsync(Guid appId); Task FindAppAsync(string name); - - void SubscribeOnChanged(Action> subscriber); } } diff --git a/src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs b/src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs index b7135c6cf..632dd46e4 100644 --- a/src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs +++ b/src/Squidex.Domain.Apps.Read/Apps/Services/IAppProvider.cs @@ -8,7 +8,6 @@ using System; using System.Threading.Tasks; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Read.Apps.Services { @@ -17,7 +16,5 @@ namespace Squidex.Domain.Apps.Read.Apps.Services Task FindAppByIdAsync(Guid id); Task FindAppByNameAsync(string name); - - void Invalidate(NamedId appId); } } diff --git a/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs b/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs index 7afaae2d9..8e82a4a31 100644 --- a/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs +++ b/src/Squidex.Domain.Apps.Read/Apps/Services/Implementations/CachingAppProvider.cs @@ -9,19 +9,31 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; +using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Read.Apps.Repositories; using Squidex.Domain.Apps.Read.Utils; using Squidex.Infrastructure; using Squidex.Infrastructure.Caching; +using Squidex.Infrastructure.CQRS.Events; +using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations { - public class CachingAppProvider : CachingProviderBase, IAppProvider + public class CachingAppProvider : CachingProviderBase, IAppProvider, IEventConsumer { private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(30); - private readonly IAppRepository repository; + public string Name + { + get { return GetType().Name; } + } + + public string EventsFilter + { + get { return string.Empty; } + } + public CachingAppProvider(IMemoryCache cache, IAppRepository repository) : base(cache) { @@ -70,16 +82,26 @@ namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations return result; } - public void Invalidate(NamedId appId) + public Task On(Envelope @event) { - var cacheKeyById = BuildIdCacheKey(appId.Id); - var cacheKeyByName = BuildNameCacheKey(appId.Name); + void Remove(NamedId id) + { + var cacheKeyById = BuildIdCacheKey(id.Id); + var cacheKeyByName = BuildNameCacheKey(id.Name); - Cache.Remove(cacheKeyById); - Cache.Remove(cacheKeyByName); + Cache.Remove(cacheKeyById); + Cache.Remove(cacheKeyByName); - Cache.Invalidate(cacheKeyById); - Cache.Invalidate(cacheKeyByName); + Cache.Invalidate(cacheKeyById); + Cache.Invalidate(cacheKeyByName); + } + + if (@event.Payload is AppEvent appEvent) + { + Remove(appEvent.AppId); + } + + return TaskHelper.Done; } private static string BuildNameCacheKey(string name) @@ -91,5 +113,10 @@ namespace Squidex.Domain.Apps.Read.Apps.Services.Implementations { return $"App_Names_{schemaId}"; } + + public Task ClearAsync() + { + return TaskHelper.Done; + } } } diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs b/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs index 73f17a933..147e4d1a9 100644 --- a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs +++ b/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaRepository.cs @@ -9,7 +9,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Read.Schemas.Repositories { @@ -20,7 +19,5 @@ namespace Squidex.Domain.Apps.Read.Schemas.Repositories Task FindSchemaAsync(Guid appId, string name); Task FindSchemaAsync(Guid schemaId); - - void SubscribeOnChanged(Action, NamedId> subscriber); } } diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs b/src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs index afd3af03c..6d50efe1a 100644 --- a/src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs +++ b/src/Squidex.Domain.Apps.Read/Schemas/Services/ISchemaProvider.cs @@ -8,7 +8,6 @@ using System; using System.Threading.Tasks; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Read.Schemas.Services { @@ -17,7 +16,5 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services Task FindSchemaByIdAsync(Guid id, bool provideDeleted = false); Task FindSchemaByNameAsync(Guid appId, string name); - - void Invalidate(NamedId appId, NamedId schemaId); } } diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs b/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs index f5355c30f..e7d0ef9e1 100644 --- a/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs +++ b/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs @@ -9,19 +9,31 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Memory; +using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Read.Schemas.Repositories; using Squidex.Domain.Apps.Read.Utils; using Squidex.Infrastructure; using Squidex.Infrastructure.Caching; +using Squidex.Infrastructure.CQRS.Events; +using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations { - public class CachingSchemaProvider : CachingProviderBase, ISchemaProvider + public class CachingSchemaProvider : CachingProviderBase, ISchemaProvider, IEventConsumer { private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); - private readonly ISchemaRepository repository; + public string Name + { + get { return GetType().Name; } + } + + public string EventsFilter + { + get { return string.Empty; } + } + public CachingSchemaProvider(IMemoryCache cache, ISchemaRepository repository) : base(cache) { @@ -80,16 +92,26 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations return result; } - public void Invalidate(NamedId appId, NamedId schemaId) + public Task On(Envelope @event) { - var cacheKeyById = BuildIdCacheKey(schemaId.Id); - var cacheKeyByName = BuildNameCacheKey(appId.Id, schemaId.Name); + void Remove(NamedId appId, NamedId schemaId) + { + var cacheKeyById = BuildIdCacheKey(schemaId.Id); + var cacheKeyByName = BuildNameCacheKey(appId.Id, schemaId.Name); - Cache.Remove(cacheKeyById); - Cache.Remove(cacheKeyByName); + Cache.Remove(cacheKeyById); + Cache.Remove(cacheKeyByName); - Cache.Invalidate(cacheKeyById); - Cache.Invalidate(cacheKeyByName); + Cache.Invalidate(cacheKeyById); + Cache.Invalidate(cacheKeyByName); + } + + if (@event.Payload is SchemaEvent schemaEvent) + { + Remove(schemaEvent.AppId, schemaEvent.SchemaId); + } + + return TaskHelper.Done; } private static string BuildNameCacheKey(Guid appId, string name) @@ -101,5 +123,10 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations { return $"Schema_Names_{schemaId}"; } + + public Task ClearAsync() + { + return TaskHelper.Done; + } } } diff --git a/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs b/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs index 3eb75d418..df5dfdf2e 100644 --- a/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs +++ b/src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs @@ -44,7 +44,7 @@ namespace Squidex.Infrastructure.CQRS.Events connectionFactory = new ConnectionFactory { Uri = new Uri(uri, UriKind.Absolute) }; connection = new Lazy(connectionFactory.CreateConnection); - channel = new Lazy(() => connection.Value.CreateModel()); + channel = new Lazy(connection.Value.CreateModel); this.exchange = exchange; this.eventsFilter = eventsFilter; diff --git a/src/Squidex/Config/Domain/InfrastructureModule.cs b/src/Squidex/Config/Domain/InfrastructureModule.cs index ea0dc246e..67e0e731c 100644 --- a/src/Squidex/Config/Domain/InfrastructureModule.cs +++ b/src/Squidex/Config/Domain/InfrastructureModule.cs @@ -15,8 +15,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Newtonsoft.Json; using NodaTime; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Core.Schemas.Json; using Squidex.Infrastructure; using Squidex.Infrastructure.Actors; using Squidex.Infrastructure.Assets; diff --git a/src/Squidex/Config/Domain/Serializers.cs b/src/Squidex/Config/Domain/Serializers.cs index 5e05fe982..185a1c3a2 100644 --- a/src/Squidex/Config/Domain/Serializers.cs +++ b/src/Squidex/Config/Domain/Serializers.cs @@ -60,8 +60,6 @@ namespace Squidex.Config.Domain TypeNameRegistry.Map(typeof(NoopEvent).GetTypeInfo().Assembly); ConfigureJson(SerializerSettings, TypeNameHandling.Auto); - - JsonConvert.DefaultSettings = () => SerializerSettings; } public static IServiceCollection AddMyEventFormatter(this IServiceCollection services) diff --git a/src/Squidex/Config/Domain/StoreMongoDbModule.cs b/src/Squidex/Config/Domain/StoreMongoDbModule.cs index 8638eb3de..f232207f3 100644 --- a/src/Squidex/Config/Domain/StoreMongoDbModule.cs +++ b/src/Squidex/Config/Domain/StoreMongoDbModule.cs @@ -13,7 +13,9 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using MongoDB.Driver; using Squidex.Domain.Apps.Read.Apps.Repositories; +using Squidex.Domain.Apps.Read.Apps.Services.Implementations; using Squidex.Domain.Apps.Read.Assets.Repositories; +using Squidex.Domain.Apps.Read.Contents.GraphQL; using Squidex.Domain.Apps.Read.Contents.Repositories; using Squidex.Domain.Apps.Read.History.Repositories; using Squidex.Domain.Apps.Read.MongoDb.Apps; @@ -23,6 +25,7 @@ using Squidex.Domain.Apps.Read.MongoDb.History; using Squidex.Domain.Apps.Read.MongoDb.Schemas; using Squidex.Domain.Apps.Read.MongoDb.Webhooks; using Squidex.Domain.Apps.Read.Schemas.Repositories; +using Squidex.Domain.Apps.Read.Schemas.Services.Implementations; using Squidex.Domain.Apps.Read.Webhooks.Repositories; using Squidex.Domain.Users; using Squidex.Domain.Users.MongoDb; @@ -144,7 +147,6 @@ namespace Squidex.Config.Domain .WithParameter(ResolvedParameter.ForNamed(MongoDatabaseRegistration)) .As() .As() - .As() .AsSelf() .SingleInstance(); @@ -152,7 +154,6 @@ namespace Squidex.Config.Domain .WithParameter(ResolvedParameter.ForNamed(MongoDatabaseRegistration)) .As() .As() - .As() .AsSelf() .SingleInstance(); @@ -185,6 +186,23 @@ namespace Squidex.Config.Domain .As() .AsSelf() .SingleInstance(); + + builder.Register(c => + new CompoundEventConsumer( + c.Resolve(), + c.Resolve(), + c.Resolve())) + .As() + .AsSelf() + .SingleInstance(); + + builder.Register(c => + new CompoundEventConsumer( + c.Resolve(), + c.Resolve())) + .As() + .AsSelf() + .SingleInstance(); } } } diff --git a/src/Squidex/Config/Domain/Usages.cs b/src/Squidex/Config/Domain/Usages.cs index a6e7c9415..d9574bfa6 100644 --- a/src/Squidex/Config/Domain/Usages.cs +++ b/src/Squidex/Config/Domain/Usages.cs @@ -9,10 +9,6 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Squidex.Domain.Apps.Read.Apps.Repositories; -using Squidex.Domain.Apps.Read.Apps.Services; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Domain.Apps.Read.Schemas.Services; using Squidex.Infrastructure; using Squidex.Infrastructure.Actors; using Squidex.Infrastructure.CQRS.Events; @@ -42,22 +38,6 @@ namespace Squidex.Config.Domain } } - var appRepository = services.GetService(); - var appProvider = services.GetService(); - - if (appProvider != null) - { - appRepository?.SubscribeOnChanged(appProvider.Invalidate); - } - - var schemaRepository = services.GetService(); - var schemaProvider = services.GetService(); - - if (schemaProvider != null) - { - schemaRepository?.SubscribeOnChanged(schemaProvider.Invalidate); - } - return app; } diff --git a/src/Squidex/Config/Identity/LazyClientStore.cs b/src/Squidex/Config/Identity/LazyClientStore.cs index 0edc892fa..b60f4688e 100644 --- a/src/Squidex/Config/Identity/LazyClientStore.cs +++ b/src/Squidex/Config/Identity/LazyClientStore.cs @@ -8,7 +8,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using IdentityServer4; using IdentityServer4.Models; diff --git a/tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs b/tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs index 2b9cfaef4..7f9a5313d 100644 --- a/tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs +++ b/tests/Squidex.Domain.Apps.Read.Tests/Apps/CachingAppProviderTests.cs @@ -11,9 +11,11 @@ using System.Threading.Tasks; using FakeItEasy; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; +using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Read.Apps.Repositories; using Squidex.Domain.Apps.Read.Apps.Services.Implementations; using Squidex.Infrastructure; +using Squidex.Infrastructure.CQRS.Events; using Xunit; namespace Squidex.Domain.Apps.Read.Apps @@ -38,6 +40,24 @@ namespace Squidex.Domain.Apps.Read.Apps sut = new CachingAppProvider(cache, repository); } + [Fact] + public void Should_return_empty_for_events_filter() + { + Assert.Equal(string.Empty, sut.EventsFilter); + } + + [Fact] + public void Should_return_empty_for_name() + { + Assert.Equal(typeof(CachingAppProvider).Name, sut.Name); + } + + [Fact] + public void Should_do_nothing_when_clearing() + { + Assert.NotNull(sut.ClearAsync()); + } + [Fact] public async Task Should_also_retrieve_app_by_name_if_retrieved_by_id_before() { @@ -65,7 +85,7 @@ namespace Squidex.Domain.Apps.Read.Apps } [Fact] - public async Task Should_clear_cache_for_id_after_invalidating() + public async Task Should_clear_cache_for_id_after_update_event() { A.CallTo(() => repository.FindAppAsync(appId.Id)) .Returns(appV2); @@ -74,7 +94,7 @@ namespace Squidex.Domain.Apps.Read.Apps await ProvideAppByIdAsync(appV1); - sut.Invalidate(appId); + sut.On(Envelope.Create(new AppLanguageAdded { AppId = appId }).To()).Wait(); await ProvideAppByIdAsync(appV2); @@ -82,7 +102,7 @@ namespace Squidex.Domain.Apps.Read.Apps } [Fact] - public async Task Should_clear_cache_for_name_after_invalidating() + public async Task Should_clear_cache_for_name_after_update_event() { A.CallTo(() => repository.FindAppAsync(appId.Name)) .Returns(appV2); @@ -91,7 +111,7 @@ namespace Squidex.Domain.Apps.Read.Apps await ProvideAppByNameAsync(appV1); - sut.Invalidate(appId); + sut.On(Envelope.Create(new AppLanguageAdded { AppId = appId }).To()).Wait(); await ProvideAppByNameAsync(appV2); diff --git a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs b/tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs index 251fbc025..03178ca21 100644 --- a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs +++ b/tests/Squidex.Domain.Apps.Read.Tests/Schemas/CachingSchemaProviderTests.cs @@ -43,6 +43,24 @@ namespace Squidex.Domain.Apps.Read.Schemas sut = new CachingSchemaProvider(cache, repository); } + [Fact] + public void Should_return_empty_for_events_filter() + { + Assert.Equal(string.Empty, sut.EventsFilter); + } + + [Fact] + public void Should_return_empty_for_name() + { + Assert.Equal(typeof(CachingSchemaProvider).Name, sut.Name); + } + + [Fact] + public void Should_do_nothing_when_clearing() + { + Assert.NotNull(sut.ClearAsync()); + } + [Fact] public async Task Should_also_retrieve_schema_by_name_if_retrieved_by_id_before() { @@ -70,7 +88,7 @@ namespace Squidex.Domain.Apps.Read.Schemas } [Fact] - public async Task Should_clear_cache_for_id_after_invalidating() + public async Task Should_clear_cache_for_id_after_update_event() { A.CallTo(() => repository.FindSchemaAsync(schemaId.Id)) .Returns(schemaV2); @@ -79,7 +97,7 @@ namespace Squidex.Domain.Apps.Read.Schemas await ProvideSchemaById(schemaV1); - sut.Invalidate(appId, schemaId); + sut.On(Envelope.Create(new FieldAdded { AppId = appId, SchemaId = schemaId })).Wait(); await ProvideSchemaById(schemaV2); @@ -87,7 +105,7 @@ namespace Squidex.Domain.Apps.Read.Schemas } [Fact] - public async Task Should_clear_cache_for_name_after_invalidating() + public async Task Should_clear_cache_for_name_after_update_event() { A.CallTo(() => repository.FindSchemaAsync(appId.Id, schemaId.Name)) .Returns(schemaV2); @@ -96,7 +114,7 @@ namespace Squidex.Domain.Apps.Read.Schemas await ProvideSchemaByName(schemaV1); - sut.Invalidate(appId, schemaId); + sut.On(Envelope.Create(new SchemaUpdated { AppId = appId, SchemaId = schemaId })).Wait(); await ProvideSchemaByName(schemaV2); diff --git a/tests/Squidex.Infrastructure.Tests/Json/ConverterContractResolverTests.cs b/tests/Squidex.Infrastructure.Tests/Json/ConverterContractResolverTests.cs index ba92a6551..31f81d172 100644 --- a/tests/Squidex.Infrastructure.Tests/Json/ConverterContractResolverTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Json/ConverterContractResolverTests.cs @@ -31,7 +31,7 @@ namespace Squidex.Infrastructure.Json public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - throw new NotImplementedException(); + throw new NotSupportedException(); } public override bool CanConvert(Type objectType)