diff --git a/src/Squidex.Infrastructure/Commands/CustomCommandMiddlewareRunner.cs b/src/Squidex.Infrastructure/Commands/CustomCommandMiddlewareRunner.cs new file mode 100644 index 000000000..556f7d1f8 --- /dev/null +++ b/src/Squidex.Infrastructure/Commands/CustomCommandMiddlewareRunner.cs @@ -0,0 +1,41 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Squidex.Infrastructure.Commands +{ + public sealed class CustomCommandMiddlewareRunner : ICommandMiddleware + { + private readonly IEnumerable extensions; + + public CustomCommandMiddlewareRunner(IEnumerable extensions) + { + Guard.NotNull(extensions, nameof(extensions)); + + this.extensions = extensions.Reverse().ToList(); + } + + public async Task HandleAsync(CommandContext context, Func next) + { + foreach (var handler in extensions) + { + next = Join(handler, context, next); + } + + await next(); + } + + private static Func Join(ICommandMiddleware handler, CommandContext context, Func next) + { + return () => handler.HandleAsync(context, next); + } + } +} diff --git a/src/Squidex.Infrastructure/Commands/ICustomCommandMiddleware.cs b/src/Squidex.Infrastructure/Commands/ICustomCommandMiddleware.cs new file mode 100644 index 000000000..e0413288f --- /dev/null +++ b/src/Squidex.Infrastructure/Commands/ICustomCommandMiddleware.cs @@ -0,0 +1,13 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Infrastructure.Commands +{ + public interface ICustomCommandMiddleware : ICommandMiddleware + { + } +} diff --git a/src/Squidex/Config/Domain/EntitiesServices.cs b/src/Squidex/Config/Domain/EntitiesServices.cs index d122a072a..c2693fffc 100644 --- a/src/Squidex/Config/Domain/EntitiesServices.cs +++ b/src/Squidex/Config/Domain/EntitiesServices.cs @@ -227,6 +227,9 @@ namespace Squidex.Config.Domain services.AddSingletonAs() .As(); + services.AddSingletonAs() + .As(); + services.AddSingletonAs() .As(); diff --git a/tests/Squidex.Infrastructure.Tests/Commands/CustomCommandMiddlewareRunnerTests.cs b/tests/Squidex.Infrastructure.Tests/Commands/CustomCommandMiddlewareRunnerTests.cs new file mode 100644 index 000000000..955907617 --- /dev/null +++ b/tests/Squidex.Infrastructure.Tests/Commands/CustomCommandMiddlewareRunnerTests.cs @@ -0,0 +1,72 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FakeItEasy; +using Xunit; + +namespace Squidex.Infrastructure.Commands +{ + public class CustomCommandMiddlewareRunnerTests + { + public sealed class Command : ICommand + { + public List Values { get; set; } = new List(); + + public long ExpectedVersion { get; set; } + } + + public sealed class CustomMiddleware : ICustomCommandMiddleware + { + private readonly int value; + + public CustomMiddleware(int value) + { + this.value = value; + } + + public Task HandleAsync(CommandContext context, Func next) + { + if (context.Command is Command command) + { + command.Values.Add(value); + } + + return next(); + } + } + + [Fact] + public async Task Should_run_extensions_in_right_order() + { + var command = new Command(); + var context = new CommandContext(command, A.Fake()); + + var sut = new CustomCommandMiddlewareRunner(new[] + { + new CustomMiddleware(10), + new CustomMiddleware(12), + new CustomMiddleware(14) + }); + + var isNextCalled = false; + + await sut.HandleAsync(context, () => + { + isNextCalled = true; + + Assert.Equal(new[] { 10, 12, 14 }, command.Values); + + return Task.CompletedTask; + }); + + Assert.True(isNextCalled); + } + } +}