From d1ee8add0cfc3da8b0ec9a41e44c537b495e2728 Mon Sep 17 00:00:00 2001 From: Dan Clark Date: Mon, 25 Nov 2024 09:44:12 +0000 Subject: [PATCH] Pipelines --- Toolkit.Foundation/AsyncHandlerDelegate.cs | 3 ++ .../AsyncHandlerInitialization.cs | 49 ++++++++++++++---- .../AsyncHandlerKeyedInitialization.cs | 51 +++++++++++++++---- Toolkit.Foundation/HandlerDelegate.cs | 3 +- Toolkit.Foundation/HandlerInitialization.cs | 44 +++++++++++++--- .../HandlerKeyedInitialization.cs | 46 ++++++++++++++--- Toolkit.Foundation/IAsyncPipelineBehavior.cs | 8 +++ Toolkit.Foundation/IPipelineBehavior.cs | 9 ++++ .../IServiceCollectionExtensions.cs | 20 +++++++- 9 files changed, 197 insertions(+), 36 deletions(-) create mode 100644 Toolkit.Foundation/AsyncHandlerDelegate.cs create mode 100644 Toolkit.Foundation/IAsyncPipelineBehavior.cs create mode 100644 Toolkit.Foundation/IPipelineBehavior.cs diff --git a/Toolkit.Foundation/AsyncHandlerDelegate.cs b/Toolkit.Foundation/AsyncHandlerDelegate.cs new file mode 100644 index 0000000..bc2a07c --- /dev/null +++ b/Toolkit.Foundation/AsyncHandlerDelegate.cs @@ -0,0 +1,3 @@ +namespace Toolkit.Foundation; + +public delegate Task AsyncHandlerDelegate(); \ No newline at end of file diff --git a/Toolkit.Foundation/AsyncHandlerInitialization.cs b/Toolkit.Foundation/AsyncHandlerInitialization.cs index 04ddf2e..4daaf1a 100644 --- a/Toolkit.Foundation/AsyncHandlerInitialization.cs +++ b/Toolkit.Foundation/AsyncHandlerInitialization.cs @@ -5,19 +5,35 @@ namespace Toolkit.Foundation; public class AsyncHandlerInitialization(IServiceProvider provider) : IInitialization where THandler : class, IAsyncHandler - where TMessage : class + where TMessage : class { public void Initialize() { if (!StrongReferenceMessenger.Default.IsRegistered>(provider)) { StrongReferenceMessenger.Default.Register>(provider, - (provider, args) => + async (provider, args) => { - foreach (IAsyncHandler handler in provider.GetServices>()) + IEnumerable> handlers = provider.GetServices>(); + IEnumerable> behaviors = provider.GetServices>(); + + AsyncHandlerDelegate handlerDelegate = async () => { - args.Reply(handler.Handle(args.Message, args.CancellationToken)); + TResponse response = default!; + foreach (IAsyncHandler handler in handlers) + { + response = await handler.Handle(args.Message, args.CancellationToken); + } + return response; + }; + + foreach (IAsyncPipelineBehavior behavior in behaviors.Reverse()) + { + AsyncHandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + args.Reply(await handlerDelegate()); }); } } @@ -25,20 +41,35 @@ public class AsyncHandlerInitialization(IServiceP public class AsyncHandlerInitialization(IServiceProvider provider) : IInitialization where THandler : class, IAsyncHandler - where TMessage : class + where TMessage : class { public void Initialize() { if (!StrongReferenceMessenger.Default.IsRegistered>(provider)) { StrongReferenceMessenger.Default.Register>(provider, - (provider, args) => + async (provider, args) => { - foreach (IAsyncHandler handler in provider.GetServices>()) + IEnumerable> handlers = provider.GetServices>(); + IEnumerable> behaviors = provider.GetServices>(); + + AsyncHandlerDelegate handlerDelegate = async () => { - handler.Handle(args.Message, args.CancellationToken); - args.Reply(Unit.Value); + foreach (IAsyncHandler handler in handlers) + { + await handler.Handle(args.Message, args.CancellationToken); + } + return Unit.Value; + }; + + foreach (IAsyncPipelineBehavior behavior in behaviors.Reverse()) + { + AsyncHandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + await handlerDelegate(); + args.Reply(Unit.Value); }); } } diff --git a/Toolkit.Foundation/AsyncHandlerKeyedInitialization.cs b/Toolkit.Foundation/AsyncHandlerKeyedInitialization.cs index 27926c5..7b7b0c1 100644 --- a/Toolkit.Foundation/AsyncHandlerKeyedInitialization.cs +++ b/Toolkit.Foundation/AsyncHandlerKeyedInitialization.cs @@ -5,20 +5,35 @@ namespace Toolkit.Foundation; public class AsyncHandlerKeyedInitialization(string key, IServiceProvider provider) : IInitialization where THandler : class, IAsyncHandler - where TMessage : class + where TMessage : class { public void Initialize() { if (!StrongReferenceMessenger.Default.IsRegistered, string>(provider, key)) { StrongReferenceMessenger.Default.Register, string>(provider, key, - (provider, args) => + async (provider, args) => { - foreach (IAsyncHandler handler in provider.GetKeyedServices>(key)) + IEnumerable> handlers = provider.GetKeyedServices>(key); + IEnumerable> behaviors = provider.GetServices>(); + + AsyncHandlerDelegate handlerDelegate = async () => { - handler.Handle(args.Message, args.CancellationToken); - args.Reply(Unit.Value); + foreach (IAsyncHandler handler in handlers) + { + await handler.Handle(args.Message, args.CancellationToken); + } + return Unit.Value; + }; + + foreach (IAsyncPipelineBehavior behavior in behaviors.Reverse()) + { + AsyncHandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + await handlerDelegate(); + args.Reply(Unit.Value); }); } } @@ -26,20 +41,36 @@ public class AsyncHandlerKeyedInitialization(string key, ISe public class AsyncHandlerKeyedInitialization(string key, IServiceProvider provider) : IInitialization where THandler : class, IAsyncHandler - where TMessage : class + where TMessage : class { public void Initialize() { if (!StrongReferenceMessenger.Default.IsRegistered, string>(provider, key)) { StrongReferenceMessenger.Default.Register, string>(provider, key, - (provider, args) => + async (provider, args) => { - foreach (IAsyncHandler handler in provider.GetKeyedServices>(key)) + IEnumerable> handlers = provider.GetKeyedServices>(key); + IEnumerable> behaviors = provider.GetServices>(); + + AsyncHandlerDelegate handlerDelegate = async () => { - args.Reply(handler.Handle(args.Message, args.CancellationToken)); + TResponse response = default!; + foreach (IAsyncHandler handler in handlers) + { + response = await handler.Handle(args.Message, args.CancellationToken); + } + return response; + }; + + foreach (IAsyncPipelineBehavior behavior in behaviors.Reverse()) + { + AsyncHandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + args.Reply(await handlerDelegate()); }); } } -} \ No newline at end of file +} diff --git a/Toolkit.Foundation/HandlerDelegate.cs b/Toolkit.Foundation/HandlerDelegate.cs index 455c50c..60bb37e 100644 --- a/Toolkit.Foundation/HandlerDelegate.cs +++ b/Toolkit.Foundation/HandlerDelegate.cs @@ -1,4 +1,3 @@ namespace Toolkit.Foundation; -public delegate Task HandlerDelegate(TRequest request, - CancellationToken cancellationToken); \ No newline at end of file +public delegate TResponse HandlerDelegate(); \ No newline at end of file diff --git a/Toolkit.Foundation/HandlerInitialization.cs b/Toolkit.Foundation/HandlerInitialization.cs index 639e9b3..dc6deb1 100644 --- a/Toolkit.Foundation/HandlerInitialization.cs +++ b/Toolkit.Foundation/HandlerInitialization.cs @@ -5,7 +5,7 @@ namespace Toolkit.Foundation; public class HandlerInitialization(IServiceProvider provider) : IInitialization where THandler : class, IHandler - where TMessage : class + where TMessage : class { public void Initialize() { @@ -14,10 +14,26 @@ public class HandlerInitialization(IServiceProvid StrongReferenceMessenger.Default.Register>(provider, (provider, args) => { - foreach (IHandler handler in provider.GetServices>()) + IEnumerable> handlers = provider.GetServices>(); + IEnumerable> behaviors = provider.GetServices>(); + + HandlerDelegate handlerDelegate = () => { - handler.Handle(args.Message); + TResponse response = default!; + foreach (IHandler handler in handlers) + { + response = handler.Handle(args.Message); + } + return response; + }; + + foreach (IPipelineBehavior behavior in behaviors.Reverse()) + { + HandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + handlerDelegate(); }); } } @@ -25,7 +41,7 @@ public class HandlerInitialization(IServiceProvid public class HandlerInitialization(IServiceProvider provider) : IInitialization where THandler : class, IHandler - where TMessage : class + where TMessage : class { public void Initialize() { @@ -34,11 +50,27 @@ public class HandlerInitialization(IServiceProvider provider StrongReferenceMessenger.Default.Register(provider, (provider, args) => { - foreach (IHandler handler in provider.GetServices>()) + IEnumerable> handlers = provider.GetServices>(); + IEnumerable> behaviors = provider.GetServices>(); + + HandlerDelegate handlerDelegate = () => { - handler.Handle(args); + foreach (IHandler handler in handlers) + { + handler.Handle(args); + } + return Unit.Value; + }; + + foreach (IPipelineBehavior behavior in behaviors.Reverse()) + { + HandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args, next); } + + handlerDelegate(); }); } } } + diff --git a/Toolkit.Foundation/HandlerKeyedInitialization.cs b/Toolkit.Foundation/HandlerKeyedInitialization.cs index fd82f27..ac55c4b 100644 --- a/Toolkit.Foundation/HandlerKeyedInitialization.cs +++ b/Toolkit.Foundation/HandlerKeyedInitialization.cs @@ -5,7 +5,7 @@ namespace Toolkit.Foundation; public class HandlerKeyedInitialization(string key, IServiceProvider provider) : IInitialization where THandler : class, IHandler - where TMessage : class + where TMessage : class { public void Initialize() { @@ -14,18 +14,34 @@ public class HandlerKeyedInitialization(string key, IService StrongReferenceMessenger.Default.Register(provider, key, (provider, args) => { - foreach (IHandler handler in provider.GetKeyedServices>(key)) + IEnumerable> handlers = provider.GetKeyedServices>(key); + IEnumerable> behaviors = provider.GetServices>(); + + HandlerDelegate handlerDelegate = () => { - handler.Handle(args); + foreach (IHandler handler in handlers) + { + handler.Handle(args); + } + return Unit.Value; + }; + + foreach (IPipelineBehavior behavior in behaviors.Reverse()) + { + HandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args, next); } + + handlerDelegate(); }); } } } + public class HandlerKeyedInitialization(string key, IServiceProvider provider) : IInitialization where THandler : class, IHandler - where TMessage : class + where TMessage : class { public void Initialize() { @@ -34,11 +50,27 @@ public class HandlerKeyedInitialization(string ke StrongReferenceMessenger.Default.Register, string>(provider, key, (provider, args) => { - foreach (IHandler handler in provider.GetKeyedServices>(key)) + IEnumerable> handlers = provider.GetKeyedServices>(key); + IEnumerable> behaviors = provider.GetServices>(); + + HandlerDelegate handlerDelegate = () => { - handler.Handle(args.Message); + TResponse response = default!; + foreach (IHandler handler in handlers) + { + response = handler.Handle(args.Message); + } + return response; + }; + + foreach (IPipelineBehavior behavior in behaviors.Reverse()) + { + HandlerDelegate next = handlerDelegate; + handlerDelegate = () => behavior.Handle(args.Message, next); } + + handlerDelegate(); }); } } -} \ No newline at end of file +} diff --git a/Toolkit.Foundation/IAsyncPipelineBehavior.cs b/Toolkit.Foundation/IAsyncPipelineBehavior.cs new file mode 100644 index 0000000..9955b12 --- /dev/null +++ b/Toolkit.Foundation/IAsyncPipelineBehavior.cs @@ -0,0 +1,8 @@ +namespace Toolkit.Foundation; + +public interface IAsyncPipelineBehavior +{ + Task Handle(TMessage message, + AsyncHandlerDelegate next); +} \ No newline at end of file diff --git a/Toolkit.Foundation/IPipelineBehavior.cs b/Toolkit.Foundation/IPipelineBehavior.cs new file mode 100644 index 0000000..f29b682 --- /dev/null +++ b/Toolkit.Foundation/IPipelineBehavior.cs @@ -0,0 +1,9 @@ +namespace Toolkit.Foundation; + +public interface IPipelineBehavior +{ + TResponse Handle(TMessage message, + HandlerDelegate next); +} + diff --git a/Toolkit.Foundation/IServiceCollectionExtensions.cs b/Toolkit.Foundation/IServiceCollectionExtensions.cs index 9173065..0a793f8 100644 --- a/Toolkit.Foundation/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/IServiceCollectionExtensions.cs @@ -124,7 +124,7 @@ public static class IServiceCollectionExtensions where THandler : class, IHandler where TMessage : class { - if (key is { Length: > 0}) + if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IHandler), key, typeof(THandler), lifetime)); services.AddInitialization>>(key); @@ -158,7 +158,7 @@ public static class IServiceCollectionExtensions return services; } - public static IServiceCollection AddInitialization(this IServiceCollection services, + public static IServiceCollection AddInitialization(this IServiceCollection services, params object[] parameters) where TInitialization : class, IInitialization @@ -167,6 +167,22 @@ public static class IServiceCollectionExtensions return services; } + public static IServiceCollection AddAsyncPipelineBehavior(this IServiceCollection services) + where TBehavior : class, + IAsyncPipelineBehavior + { + services.AddTransient, TBehavior>(); + return services; + } + + public static IServiceCollection AddPipelineBehavior(this IServiceCollection services) + where TBehavior : class, + IPipelineBehavior + { + services.AddTransient, TBehavior>(); + return services; + } + public static IServiceCollection AddRange(this IServiceCollection services, IServiceCollection fromServices) {