diff --git a/.gitignore b/.gitignore index 776cf7c..98b2ca4 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,10 @@ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +**/obj/ +**/bin/ +# Vs code settings +**/.vscode/ # Visual Studio 2015 cache/options directory .vs/ diff --git a/src/PipelineNet.Tests/ChainsOfResponsibility/AsyncResponsibilityChainTests.cs b/src/PipelineNet.Tests/ChainsOfResponsibility/AsyncResponsibilityChainTests.cs index 2dcb5b2..725d53c 100644 --- a/src/PipelineNet.Tests/ChainsOfResponsibility/AsyncResponsibilityChainTests.cs +++ b/src/PipelineNet.Tests/ChainsOfResponsibility/AsyncResponsibilityChainTests.cs @@ -1,6 +1,5 @@ using PipelineNet.ChainsOfResponsibility; using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; using System.Threading.Tasks; using Xunit; @@ -93,7 +92,7 @@ public async Task Run(Exception exception, Func> exe [Fact] public async Task Execute_CreateChainOfMiddlewareToHandleException_TheRightMiddleHandlesTheException() { - var responsibilityChain = new AsyncResponsibilityChain(new ActivatorMiddlewareResolver()) + var responsibilityChain = new AsyncResponsibilityChain() .Chain() .Chain() .Chain(); @@ -113,7 +112,7 @@ public async Task Execute_CreateChainOfMiddlewareToHandleException_TheRightMiddl [Fact] public async Task Execute_ChainOfMiddlewareThatDoesNotHandleTheException_ChainReturnsDefaultValue() { - var responsibilityChain = new AsyncResponsibilityChain(new ActivatorMiddlewareResolver()) + var responsibilityChain = new AsyncResponsibilityChain() .Chain() .Chain() .Chain(); @@ -127,54 +126,13 @@ public async Task Execute_ChainOfMiddlewareThatDoesNotHandleTheException_ChainRe Assert.Equal(default(bool), result); } - [Fact] - public async Task Execute_ChainOfMiddlewareWithFinallyFunc_FinallyFuncIsExecuted() - { - const string ExceptionSource = "EXCEPTION_SOURCE"; - - var responsibilityChain = new AsyncResponsibilityChain(new ActivatorMiddlewareResolver()) - .Chain() - .Chain(typeof(InvalidateDataExceptionHandler)) - .Chain() - .Finally((ex) => - { - ex.Source = ExceptionSource; - return Task.FromResult(true); - }); - - // Creates an ArgumentNullException, that will not be handled by any middleware. - var exception = new ArgumentNullException(); - - // The result should true, since the finally function will be executed. - var result = await responsibilityChain.Execute(exception); - - Assert.True(result); - - Assert.Equal(ExceptionSource, exception.Source); - } - - /// - /// Tests the method. - /// - [Fact] - public void Chain_AddTypeThatIsNotAMiddleware_ThrowsException() - { - var responsibilityChain = new AsyncResponsibilityChain(new ActivatorMiddlewareResolver()); - Assert.Throws(() => - { - responsibilityChain.Chain(typeof(ResponsibilityChainTests)); - }); - } - - - /// /// Try to generate a deadlock in synchronous middleware. /// [Fact] public void Execute_SynchronousChainOfResponsibility_SuccessfullyExecute() { - var responsibilityChain = new AsyncResponsibilityChain(new ActivatorMiddlewareResolver()) + var responsibilityChain = new AsyncResponsibilityChain() .Chain() .Chain() .Finally(input => Task.FromResult(input)); diff --git a/src/PipelineNet.Tests/ChainsOfResponsibility/ResponsibilityChainTests.cs b/src/PipelineNet.Tests/ChainsOfResponsibility/ResponsibilityChainTests.cs index 65d0767..ea6f37a 100644 --- a/src/PipelineNet.Tests/ChainsOfResponsibility/ResponsibilityChainTests.cs +++ b/src/PipelineNet.Tests/ChainsOfResponsibility/ResponsibilityChainTests.cs @@ -1,6 +1,5 @@ using PipelineNet.ChainsOfResponsibility; using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; using Xunit; @@ -68,7 +67,7 @@ public bool Run(Exception exception, Func executeNext) [Fact] public void Execute_CreateChainOfMiddlewareToHandleException_TheRightMiddleHandlesTheException() { - var responsibilityChain = new ResponsibilityChain(new ActivatorMiddlewareResolver()) + var responsibilityChain = new ResponsibilityChain() .Chain() .Chain() .Chain(); @@ -88,7 +87,7 @@ public void Execute_CreateChainOfMiddlewareToHandleException_TheRightMiddleHandl [Fact] public void Execute_ChainOfMiddlewareThatDoesNotHandleTheException_ChainReturnsDefaultValue() { - var responsibilityChain = new ResponsibilityChain(new ActivatorMiddlewareResolver()) + var responsibilityChain = new ResponsibilityChain() .Chain() .Chain() .Chain(); @@ -101,44 +100,5 @@ public void Execute_ChainOfMiddlewareThatDoesNotHandleTheException_ChainReturnsD Assert.Equal(default(bool), result); } - - [Fact] - public void Execute_ChainOfMiddlewareWithFinallyFunc_FinallyFuncIsExecuted() - { - const string ExceptionSource = "EXCEPTION_SOURCE"; - - var responsibilityChain = new ResponsibilityChain(new ActivatorMiddlewareResolver()) - .Chain() - .Chain(typeof(InvalidateDataExceptionHandler)) - .Chain() - .Finally((ex) => - { - ex.Source = ExceptionSource; - return true; - }); - - // Creates an ArgumentNullException, that will not be handled by any middleware. - var exception = new ArgumentNullException(); - - // The result should true, since the finally function will be executed. - var result = responsibilityChain.Execute(exception); - - Assert.True(result); - - Assert.Equal(ExceptionSource, exception.Source); - } - - /// - /// Tests the method. - /// - [Fact] - public void Chain_AddTypeThatIsNotAMiddleware_ThrowsException() - { - var responsibilityChain = new ResponsibilityChain(new ActivatorMiddlewareResolver()); - Assert.Throws(() => - { - responsibilityChain.Chain(typeof(ResponsibilityChainTests)); - }); - } } } diff --git a/src/PipelineNet.Tests/MethodsChains/MethodsChain.cs b/src/PipelineNet.Tests/MethodsChains/MethodsChain.cs new file mode 100644 index 0000000..d54d0aa --- /dev/null +++ b/src/PipelineNet.Tests/MethodsChains/MethodsChain.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using PipelineNet.MethodsChains; +using Xunit; + +namespace PipelineNet.Tests.MethodsChains{ + public class MethodsChainsTests{ + [Fact] + public void NumberTransform(){ + var chain = MethodsChain + .Chain(num=>(1+num).ToString()) + .Chain(numStr=>numStr+"2") + .Chain(int.Parse); + var expected = 12352; + var actual = chain.Run(1234); + Assert.Equal(expected,actual); + } + [Fact] + public void MethodAbortion(){ + bool reachedEnd = false; + var chain = MethodsChain + .Chain(num=>num+1) + .Chain(num=>num % 3 == 0 ? num/3 - 1 : throw new Exception()) + .Chain(num=>{ + reachedEnd = true; + return num+1 % 2 == 0 ? "yes" : "no"; + }); + Assert.Throws(()=>chain.Run(25)); + Assert.False(reachedEnd); + } + [Fact] + public void WithoutReturnType(){ + var result = new List(); + var doubleResult = new List(); + var chain = MethodsChain + .Chain(num=>(1+num).ToString()) + .Chain(numStr=>numStr+"2") + .Chain(int.Parse) + .Chain(result.Add) + .Chain(x=>doubleResult.Add(x*2)); + + chain.Run(10); + chain.Run(20); + chain.Run(30); + + Assert.Equal(new[]{112,212,312},result); + Assert.Equal(new[]{2*112,2*212,2*312},doubleResult); + } + } +} \ No newline at end of file diff --git a/src/PipelineNet.Tests/PipelineNet.Tests.csproj b/src/PipelineNet.Tests/PipelineNet.Tests.csproj index 1d3682a..68eff19 100644 --- a/src/PipelineNet.Tests/PipelineNet.Tests.csproj +++ b/src/PipelineNet.Tests/PipelineNet.Tests.csproj @@ -1,20 +1,15 @@ - - + - netcoreapp2.1 - + net7.0 false true - - - - + + + - - + - - + \ No newline at end of file diff --git a/src/PipelineNet.Tests/Pipelines/AsyncPipelineTests.cs b/src/PipelineNet.Tests/Pipelines/AsyncPipelineTests.cs index 804681f..bdff83f 100644 --- a/src/PipelineNet.Tests/Pipelines/AsyncPipelineTests.cs +++ b/src/PipelineNet.Tests/Pipelines/AsyncPipelineTests.cs @@ -1,5 +1,4 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using PipelineNet.Pipelines; using System; using System.Text.RegularExpressions; @@ -76,7 +75,7 @@ public async Task Run(PersonModel context, Func executeNext) [Fact] public async Task Execute_RunSeveralMiddleware_SuccessfullyExecute() { - var pipeline = new AsyncPipeline(new ActivatorMiddlewareResolver()) + var pipeline = new AsyncPipeline() .Add() .Add() .Add() @@ -97,7 +96,7 @@ public async Task Execute_RunSeveralMiddleware_SuccessfullyExecute() [Fact] public async Task Execute_RunSamePipelineTwice_SuccessfullyExecute() { - var pipeline = new AsyncPipeline(new ActivatorMiddlewareResolver()) + var pipeline = new AsyncPipeline() .Add() .Add() .Add() @@ -128,39 +127,5 @@ public async Task Execute_RunSamePipelineTwice_SuccessfullyExecute() // Check if the level of 'personModel' is 4, which is configured by 'PersonWithGenderProperty' middleware. Assert.Equal(4, personModel.Level); } - - [Fact] - public async Task Execute_RunSeveralMiddlewareWithTwoBeingDynamiccalyAdded_SuccessfullyExecute() - { - var pipeline = new AsyncPipeline(new ActivatorMiddlewareResolver()) - .Add() - .Add(typeof(PersonWithOddId)) - .Add() - .Add(typeof(PersonWithGenderProperty)); - - // This person model has a gender, so the last middleware will be the one handling the input. - var personModel = new PersonModel - { - Gender = Gender.Female - }; - - await pipeline.Execute(personModel); - - // Check if the level of 'personModel' is 4, which is configured by 'PersonWithGenderProperty' middleware. - Assert.Equal(4, personModel.Level); - } - - /// - /// Tests the method. - /// - [Fact] - public void Add_AddTypeThatIsNotAMiddleware_ThrowsException() - { - var pipeline = new AsyncPipeline(new ActivatorMiddlewareResolver()); - Assert.Throws(() => - { - pipeline.Add(typeof(AsyncPipelineTests)); - }); - } } } diff --git a/src/PipelineNet.Tests/Pipelines/PipelineTests.cs b/src/PipelineNet.Tests/Pipelines/PipelineTests.cs index bafab6c..acc3d1f 100644 --- a/src/PipelineNet.Tests/Pipelines/PipelineTests.cs +++ b/src/PipelineNet.Tests/Pipelines/PipelineTests.cs @@ -1,7 +1,9 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using PipelineNet.Pipelines; using System; +using System.IO; +using System.Linq; +using System.Text; using System.Text.RegularExpressions; using Xunit; @@ -72,7 +74,7 @@ public void Run(PersonModel context, Action executeNext) [Fact] public void Execute_RunSeveralMiddleware_SuccessfullyExecute() { - var pipeline = new Pipeline(new ActivatorMiddlewareResolver()) + var pipeline = new Pipeline() .Add() .Add() .Add() @@ -93,7 +95,7 @@ public void Execute_RunSeveralMiddleware_SuccessfullyExecute() [Fact] public void Execute_RunSamePipelineTwice_SuccessfullyExecute() { - var pipeline = new Pipeline(new ActivatorMiddlewareResolver()) + var pipeline = new Pipeline() .Add() .Add() .Add() @@ -104,7 +106,6 @@ public void Execute_RunSamePipelineTwice_SuccessfullyExecute() { Name = "this_is_my_email@servername.js" }; - pipeline.Execute(personModel); // Check if the level of 'personModel' is 3, which is configured by 'PersonWithEmailName' middleware. @@ -124,39 +125,5 @@ public void Execute_RunSamePipelineTwice_SuccessfullyExecute() // Check if the level of 'personModel' is 4, which is configured by 'PersonWithGenderProperty' middleware. Assert.Equal(4, personModel.Level); } - - [Fact] - public void Execute_RunSeveralMiddlewareWithTwoBeingDynamiccalyAdded_SuccessfullyExecute() - { - var pipeline = new Pipeline(new ActivatorMiddlewareResolver()) - .Add() - .Add(typeof(PersonWithOddId)) - .Add() - .Add(typeof(PersonWithGenderProperty)); - - // This person model has a gender, so the last middleware will be the one handling the input. - var personModel = new PersonModel - { - Gender = Gender.Female - }; - - pipeline.Execute(personModel); - - // Check if the level of 'personModel' is 4, which is configured by 'PersonWithGenderProperty' middleware. - Assert.Equal(4, personModel.Level); - } - - /// - /// Tests the method. - /// - [Fact] - public void Add_AddTypeThatIsNotAMiddleware_ThrowsException() - { - var pipeline = new Pipeline(new ActivatorMiddlewareResolver()); - Assert.Throws(() => - { - pipeline.Add(typeof(PipelineTests)); - }); - } } } diff --git a/src/PipelineNet/BaseMiddlewareFlow.cs b/src/PipelineNet/BaseMiddlewareFlow.cs index 99ccdb6..54705d3 100644 --- a/src/PipelineNet/BaseMiddlewareFlow.cs +++ b/src/PipelineNet/BaseMiddlewareFlow.cs @@ -1,45 +1,11 @@ -using PipelineNet.MiddlewareResolver; -using System; using System.Collections.Generic; -using System.Reflection; +using PipelineNet.Middleware; namespace PipelineNet { public abstract class BaseMiddlewareFlow { - protected IList MiddlewareTypes { get; private set; } - protected IMiddlewareResolver MiddlewareResolver { get; private set; } + public List Middleware{get;protected set;} = new List(); - internal BaseMiddlewareFlow(IMiddlewareResolver middlewareResolver) - { - MiddlewareResolver = middlewareResolver ?? throw new ArgumentNullException("middlewareResolver", - "An instance of IMiddlewareResolver must be provided. You can use ActivatorMiddlewareResolver."); - MiddlewareTypes = new List(); - } - - /// - /// Stores the of the middleware type. - /// - private static readonly TypeInfo MiddlewareTypeInfo = typeof(TMiddleware).GetTypeInfo(); - - /// - /// Adds a new middleware type to the internal list of types. - /// Middleware will be executed in the same order they are added. - /// - /// The middleware type to be executed. - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - protected void AddMiddleware(Type middlewareType) - { - if (middlewareType == null) throw new ArgumentNullException("middlewareType"); - - bool isAssignableFromMiddleware = MiddlewareTypeInfo.IsAssignableFrom(middlewareType.GetTypeInfo()); - if (!isAssignableFromMiddleware) - throw new ArgumentException( - $"The middleware type must implement \"{typeof(TMiddleware)}\"."); - - this.MiddlewareTypes.Add(middlewareType); - } } -} +} \ No newline at end of file diff --git a/src/PipelineNet/ChainsOfResponsibility/AsyncResponsibilityChain.cs b/src/PipelineNet/ChainsOfResponsibility/AsyncResponsibilityChain.cs index a6282cf..e1a1ae5 100644 --- a/src/PipelineNet/ChainsOfResponsibility/AsyncResponsibilityChain.cs +++ b/src/PipelineNet/ChainsOfResponsibility/AsyncResponsibilityChain.cs @@ -1,6 +1,6 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace PipelineNet.ChainsOfResponsibility @@ -10,43 +10,21 @@ namespace PipelineNet.ChainsOfResponsibility /// /// The input type for the chain. /// The return type of the chain. - public class AsyncResponsibilityChain : BaseMiddlewareFlow>, - IAsyncResponsibilityChain + public class AsyncResponsibilityChain : BaseMiddlewareFlow>, IAsyncResponsibilityChain { private Func> _finallyFunc; - /// - /// Creates a new asynchronous chain of responsibility. - /// - /// The resolver used to create the middleware types. - public AsyncResponsibilityChain(IMiddlewareResolver middlewareResolver) : base(middlewareResolver) - { - } - /// /// Chains a new middleware to the chain of responsibility. /// Middleware will be executed in the same order they are added. /// /// The new middleware being added. /// The current instance of . - public IAsyncResponsibilityChain Chain() where TMiddleware : IAsyncMiddleware - { - MiddlewareTypes.Add(typeof(TMiddleware)); - return this; - } - - /// - /// Chains a new middleware type to the chain of responsibility. - /// Middleware will be executed in the same order they are added. - /// - /// The middleware type to be executed. - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - /// The current instance of . - public IAsyncResponsibilityChain Chain(Type middlewareType) + public IAsyncResponsibilityChain Chain(Action configure = null) where TMiddleware : IAsyncMiddleware, new() { - base.AddMiddleware(middlewareType); + var mw = new TMiddleware(); + configure?.Invoke(mw); + Middleware.Add(mw); return this; } @@ -56,27 +34,20 @@ public IAsyncResponsibilityChain Chain(Type middlewareType) /// public async Task Execute(TParameter parameter) { - if (MiddlewareTypes.Count == 0) - return default(TReturn); - - int index = 0; - Func> func = null; - func = (param) => - { - var type = MiddlewareTypes[index]; - var middleware = (IAsyncMiddleware)MiddlewareResolver.Resolve(type); - - index++; - // If the current instance of middleware is the last one in the list, - // the "next" function is assigned to the finally function or a - // default empty function. - if (index == MiddlewareTypes.Count) - func = this._finallyFunc ?? ((p) => Task.FromResult(default(TReturn))); - - return middleware.Run(param, func); - }; + var res = await Do(parameter,Middleware.GetEnumerator()); + return res; - return await func(parameter).ConfigureAwait(false); + async Task Do(TParameter _param,IEnumerator> e){ + + if(!e.MoveNext()){ + if(!(_finallyFunc is null)) + return await _finallyFunc?.Invoke(_param); + return default; + } + return await e.Current.Run(_param,async p=>{ + return await Do(p,e); + }); + } } /// diff --git a/src/PipelineNet/ChainsOfResponsibility/IAsyncResponsibilityChain.cs b/src/PipelineNet/ChainsOfResponsibility/IAsyncResponsibilityChain.cs index 44ec02f..4ee746a 100644 --- a/src/PipelineNet/ChainsOfResponsibility/IAsyncResponsibilityChain.cs +++ b/src/PipelineNet/ChainsOfResponsibility/IAsyncResponsibilityChain.cs @@ -26,19 +26,8 @@ public interface IAsyncResponsibilityChain /// /// The new middleware being added. /// The current instance of . - IAsyncResponsibilityChain Chain() - where TMiddleware : IAsyncMiddleware; - - /// - /// Chains a new middleware type to the chain of responsibility. - /// Middleware will be executed in the same order they are added. - /// - /// The middleware type to be executed. - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - /// The current instance of . - IAsyncResponsibilityChain Chain(Type middlewareType); + IAsyncResponsibilityChain Chain(Action configure = null) + where TMiddleware : IAsyncMiddleware, new(); /// /// Executes the configured chain of responsibility. diff --git a/src/PipelineNet/ChainsOfResponsibility/IResponsibilityChain.cs b/src/PipelineNet/ChainsOfResponsibility/IResponsibilityChain.cs index 7cf5af2..fdf8e76 100644 --- a/src/PipelineNet/ChainsOfResponsibility/IResponsibilityChain.cs +++ b/src/PipelineNet/ChainsOfResponsibility/IResponsibilityChain.cs @@ -25,19 +25,8 @@ public interface IResponsibilityChain /// /// The new middleware being added. /// The current instance of . - IResponsibilityChain Chain() - where TMiddleware : IMiddleware; - - /// - /// Chains a new middleware type to the chain of responsibility. - /// Middleware will be executed in the same order they are added. - /// - /// The middleware type to be executed. - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - /// The current instance of . - IResponsibilityChain Chain(Type middlewareType); + IResponsibilityChain Chain(Action configure = null) + where TMiddleware : IMiddleware, new(); /// /// Executes the configured chain of responsibility. diff --git a/src/PipelineNet/ChainsOfResponsibility/ResponsibilityChain.cs b/src/PipelineNet/ChainsOfResponsibility/ResponsibilityChain.cs index da238d6..f2437da 100644 --- a/src/PipelineNet/ChainsOfResponsibility/ResponsibilityChain.cs +++ b/src/PipelineNet/ChainsOfResponsibility/ResponsibilityChain.cs @@ -1,6 +1,6 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; +using System.Collections.Generic; namespace PipelineNet.ChainsOfResponsibility { @@ -9,19 +9,10 @@ namespace PipelineNet.ChainsOfResponsibility /// /// The input type for the chain. /// The return type of the chain. - public class ResponsibilityChain : BaseMiddlewareFlow>, - IResponsibilityChain + public class ResponsibilityChain : BaseMiddlewareFlow>, IResponsibilityChain { private Func _finallyFunc; - /// - /// Creates a new chain of responsibility. - /// - /// - public ResponsibilityChain(IMiddlewareResolver middlewareResolver) : base(middlewareResolver) - { - } - /// /// Sets the function to be executed at the end of the chain as a fallback. /// A chain can only have one finally function. Calling this method more @@ -41,27 +32,15 @@ public IResponsibilityChain Finally(Func /// The new middleware being added. /// The current instance of . - public IResponsibilityChain Chain() - where TMiddleware : IMiddleware + public IResponsibilityChain Chain(Action configure = null) + where TMiddleware : IMiddleware, new() { - MiddlewareTypes.Add(typeof(TMiddleware)); + var mw = new TMiddleware(); + configure?.Invoke(mw); + Middleware.Add(mw); return this; } - /// - /// Chains a new middleware type to the chain of responsibility. - /// Middleware will be executed in the same order they are added. - /// - /// The middleware type to be executed. - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - /// The current instance of . - public IResponsibilityChain Chain(Type middlewareType) - { - base.AddMiddleware(middlewareType); - return this; - } /// /// Execute the configured chain of responsibility. @@ -69,27 +48,20 @@ public IResponsibilityChain Chain(Type middlewareType) /// public TReturn Execute(TParameter parameter) { - if (MiddlewareTypes.Count == 0) - return default(TReturn); - - int index = 0; - Func func = null; - func = (param) => - { - var type = MiddlewareTypes[index]; - var middleware = (IMiddleware)MiddlewareResolver.Resolve(type); - - index++; - // If the current instance of middleware is the last one in the list, - // the "next" function is assigned to the finally function or a - // default empty function. - if (index == MiddlewareTypes.Count) - func = this._finallyFunc ?? ((p) => default(TReturn)); - - return middleware.Run(param, func); - }; + var res = Do(parameter,Middleware.GetEnumerator()); + return res; - return func(parameter); + TReturn Do(TParameter _param,IEnumerator> e){ + if(!e.MoveNext()){ + if(!(_finallyFunc is null)) + return _finallyFunc.Invoke(_param); + return default; + } + + return e.Current.Run(_param,p=>{ + return Do(p,e); + }); + } } } } diff --git a/src/PipelineNet/MethodsChains/IMethodsChain.cs b/src/PipelineNet/MethodsChains/IMethodsChain.cs new file mode 100644 index 0000000..be44730 --- /dev/null +++ b/src/PipelineNet/MethodsChains/IMethodsChain.cs @@ -0,0 +1,35 @@ +using System; + +namespace PipelineNet.MethodsChains +{ + /// + /// Pipeline-like chain of functions, thats allows continuous data transformation and + /// support execution abortion + /// + public interface IMethodsChain + { + /// + /// Used to get output from input.
+ /// Throw any exception in this method -> it will stop pipeline execution + ///
+ Func OnCall { get; } + /// + /// Chains current chain output to next chain input. In the end works like function decorator. + /// + IMethodsChain Chain(Func nextCall); + /// + /// Chains another chain + /// + IMethodsChain Chain(IMethodsChain nextCall); + /// + /// Chains current chain without output - just will pass input to next chain + /// + /// + /// + IMethodsChain Chain(Action nextCall); + /// + /// Use to get output from input.
+ ///
+ TOutput Run(TInput input); + } +} diff --git a/src/PipelineNet/MethodsChains/MethodsChain.cs b/src/PipelineNet/MethodsChains/MethodsChain.cs new file mode 100644 index 0000000..125a8d8 --- /dev/null +++ b/src/PipelineNet/MethodsChains/MethodsChain.cs @@ -0,0 +1,42 @@ +using System; + +namespace PipelineNet.MethodsChains +{ + /// + /// Methods chain implementation + /// + public class MethodsChain : IMethodsChain + { + public Func OnCall { get; set; } + + public MethodsChain(Func onCall) + { + OnCall = onCall; + } + public static IMethodsChain Chain(Func nextCall) => new MethodsChain(nextCall); + public static IMethodsChain Chain(IMethodsChain nextCall) => new MethodsChain(nextCall.Run); + public static IMethodsChain Chain(Action nextCall) => new MethodsChain(x=>{ + nextCall(x); + return x; + }); + + public IMethodsChain Chain(Func nextCall) + { + return new MethodsChain( + input => + { + TOutput output; + output = Run(input); + return nextCall(output); + } + ); + } + public IMethodsChain Chain(Action nextCall)=>Chain(x=>{ + nextCall(x); + return x; + }); + + public IMethodsChain Chain(IMethodsChain nextCall)=>Chain(nextCall.Run); + public TOutput Run(TInput input)=>OnCall(input); + } +} diff --git a/src/PipelineNet/Middleware/IAsyncMiddleware.WithReturn.cs b/src/PipelineNet/Middleware/IAsyncMiddleware.WithReturn.cs index fb7ccf5..3fe275f 100644 --- a/src/PipelineNet/Middleware/IAsyncMiddleware.WithReturn.cs +++ b/src/PipelineNet/Middleware/IAsyncMiddleware.WithReturn.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; namespace PipelineNet.Middleware @@ -7,4 +7,4 @@ public interface IAsyncMiddleware { Task Run(TParameter parameter, Func> next); } -} +} \ No newline at end of file diff --git a/src/PipelineNet/Middleware/IMiddleware.WithReturn.cs b/src/PipelineNet/Middleware/IMiddleware.WithResult.cs similarity index 90% rename from src/PipelineNet/Middleware/IMiddleware.WithReturn.cs rename to src/PipelineNet/Middleware/IMiddleware.WithResult.cs index b063101..5ff443e 100644 --- a/src/PipelineNet/Middleware/IMiddleware.WithReturn.cs +++ b/src/PipelineNet/Middleware/IMiddleware.WithResult.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace PipelineNet.Middleware { @@ -6,4 +6,4 @@ public interface IMiddleware { TReturn Run(TParameter parameter, Func next); } -} +} \ No newline at end of file diff --git a/src/PipelineNet/MiddlewareResolver/ActivatorMiddlewareResolver.cs b/src/PipelineNet/MiddlewareResolver/ActivatorMiddlewareResolver.cs deleted file mode 100644 index a96c918..0000000 --- a/src/PipelineNet/MiddlewareResolver/ActivatorMiddlewareResolver.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace PipelineNet.MiddlewareResolver -{ - /// - /// A default implementation of that creates - /// instances using the . - /// - public class ActivatorMiddlewareResolver : IMiddlewareResolver - { - public object Resolve(Type type) - { - return Activator.CreateInstance(type); - } - } -} diff --git a/src/PipelineNet/MiddlewareResolver/IMiddlewareResolver.cs b/src/PipelineNet/MiddlewareResolver/IMiddlewareResolver.cs deleted file mode 100644 index 36f4670..0000000 --- a/src/PipelineNet/MiddlewareResolver/IMiddlewareResolver.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace PipelineNet.MiddlewareResolver -{ - /// - /// Used to create instances of middleware. - /// You can implement this interface for your preferred dependency injection container. - /// - public interface IMiddlewareResolver - { - /// - /// Creates an instance of the give middleware type. - /// - /// The middleware type that will be created. - /// An instance of the middleware. - object Resolve(Type type); - } -} diff --git a/src/PipelineNet/PipelineNet.csproj b/src/PipelineNet/PipelineNet.csproj index c77e500..34d24f7 100644 --- a/src/PipelineNet/PipelineNet.csproj +++ b/src/PipelineNet/PipelineNet.csproj @@ -1,17 +1,17 @@  - netstandard1.1 + netstandard2.0 - 1.0.0 - PipelineNet - PipelineNet + 1.0.3 + Kemsekov.PipelineNet + Kemsekov.PipelineNet $(Version) Israel Valverde A micro framework that helps you implement pipeline and chain of responsibility patterns. - https://github.com/ipvalverde/PipelineNet + https://github.com/Kemsekov/PipelineNet https://github.com/ipvalverde/PipelineNet/blob/master/LICENSE Copyright © Israel Valverde Pipeline .NetCore Portable Chain Responsibility ChainOfResponsibility Core NetStandard diff --git a/src/PipelineNet/PipelineNet.sln b/src/PipelineNet/PipelineNet.sln new file mode 100644 index 0000000..fe20db5 --- /dev/null +++ b/src/PipelineNet/PipelineNet.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PipelineNet", "PipelineNet.csproj", "{2EC165B9-F596-4639-83FF-A07FE6414954}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2EC165B9-F596-4639-83FF-A07FE6414954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2EC165B9-F596-4639-83FF-A07FE6414954}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2EC165B9-F596-4639-83FF-A07FE6414954}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2EC165B9-F596-4639-83FF-A07FE6414954}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4F7D3F5D-B5B1-43EA-AE5B-D5A5EA46A9F2} + EndGlobalSection +EndGlobal diff --git a/src/PipelineNet/Pipelines/AsyncPipeline.cs b/src/PipelineNet/Pipelines/AsyncPipeline.cs index 0a2b4d8..776ae89 100644 --- a/src/PipelineNet/Pipelines/AsyncPipeline.cs +++ b/src/PipelineNet/Pipelines/AsyncPipeline.cs @@ -1,6 +1,6 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace PipelineNet.Pipelines @@ -8,34 +8,21 @@ namespace PipelineNet.Pipelines public class AsyncPipeline : BaseMiddlewareFlow>, IAsyncPipeline where TParameter : class { - public AsyncPipeline(IMiddlewareResolver middlewareResolver) : base(middlewareResolver) - {} /// /// Adds a middleware type to be executed. /// /// /// - public IAsyncPipeline Add() - where TMiddleware : IAsyncMiddleware + public IAsyncPipeline Add(Action configure = null) + where TMiddleware : IAsyncMiddleware, new() { - MiddlewareTypes.Add(typeof(TMiddleware)); + var middleware = new TMiddleware(); + configure?.Invoke(middleware); + Middleware.Add(middleware); return this; } - /// - /// Adds a middleware type to be executed. - /// - /// The middleware type to be executed. - /// - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - public IAsyncPipeline Add(Type middlewareType) - { - base.AddMiddleware(middlewareType); - return this; - } /// /// Execute the configured pipeline. @@ -43,24 +30,14 @@ public IAsyncPipeline Add(Type middlewareType) /// public async Task Execute(TParameter parameter) { - if (MiddlewareTypes.Count == 0) - return; - - int index = 0; - Func action = null; - action = async (param) => - { - var type = MiddlewareTypes[index]; - var firstMiddleware = (IAsyncMiddleware)MiddlewareResolver.Resolve(type); - - index++; - if (index == MiddlewareTypes.Count) - action = (p) => Task.FromResult(0); - - await firstMiddleware.Run(param, action).ConfigureAwait(false); - }; - - await action(parameter).ConfigureAwait(false); + await Do(parameter,Middleware.GetEnumerator()); + + async Task Do(TParameter _param,IEnumerator> e){ + if(!e.MoveNext()) return; + await e.Current.Run(_param,async p=>{ + await Do(p,e); + }); + } } } } diff --git a/src/PipelineNet/Pipelines/IAsyncPipeline.cs b/src/PipelineNet/Pipelines/IAsyncPipeline.cs index c4a5a37..5663a87 100644 --- a/src/PipelineNet/Pipelines/IAsyncPipeline.cs +++ b/src/PipelineNet/Pipelines/IAsyncPipeline.cs @@ -11,8 +11,8 @@ public interface IAsyncPipeline /// /// /// - IAsyncPipeline Add() - where TMiddleware : IAsyncMiddleware; + IAsyncPipeline Add(Action configure = null) + where TMiddleware : IAsyncMiddleware, new(); /// /// Execute the configured pipeline. @@ -20,14 +20,5 @@ IAsyncPipeline Add() /// Task Execute(TParameter parameter); - /// - /// Adds a middleware type to be executed. - /// - /// The middleware type to be executed. - /// - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - IAsyncPipeline Add(Type middlewareType); } } diff --git a/src/PipelineNet/Pipelines/IPipeline.cs b/src/PipelineNet/Pipelines/IPipeline.cs index 5e38e31..325967c 100644 --- a/src/PipelineNet/Pipelines/IPipeline.cs +++ b/src/PipelineNet/Pipelines/IPipeline.cs @@ -1,5 +1,6 @@ using PipelineNet.Middleware; using System; +using System.Threading; namespace PipelineNet.Pipelines { @@ -15,8 +16,8 @@ public interface IPipeline /// /// /// - IPipeline Add() - where TMiddleware : IMiddleware; + IPipeline Add(Action configure = null) + where TMiddleware : IMiddleware, new(); /// /// Executes the configured pipeline. @@ -24,14 +25,5 @@ IPipeline Add() /// The input that will be provided to all middleware. void Execute(TParameter parameter); - /// - /// Adds a middleware type to be executed. - /// - /// The middleware type to be executed. - /// - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - IPipeline Add(Type middlewareType); } } diff --git a/src/PipelineNet/Pipelines/Pipeline.cs b/src/PipelineNet/Pipelines/Pipeline.cs index 4153298..2bc0d63 100644 --- a/src/PipelineNet/Pipelines/Pipeline.cs +++ b/src/PipelineNet/Pipelines/Pipeline.cs @@ -1,6 +1,10 @@ using PipelineNet.Middleware; -using PipelineNet.MiddlewareResolver; using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; namespace PipelineNet.Pipelines { @@ -11,36 +15,27 @@ namespace PipelineNet.Pipelines /// The type that will be the input for all the middleware. public class Pipeline : BaseMiddlewareFlow>, IPipeline { - /// - /// Creates a new instance of Pipeline. - /// - /// Resolver responsible for resolving instances out of middleware types. - public Pipeline(IMiddlewareResolver middlewareResolver) : base(middlewareResolver) - {} - /// - /// Adds a middleware type to be executed. - /// - /// - /// - public IPipeline Add() - where TMiddleware : IMiddleware + public Pipeline() { - MiddlewareTypes.Add(typeof(TMiddleware)); - return this; - } - /// + } + /// /// Adds a middleware type to be executed. /// - /// The middleware type to be executed. + /// /// - /// Thrown if the is - /// not an implementation of . - /// Thrown if is null. - public IPipeline Add(Type middlewareType) + public IPipeline Add(Action configure = null) + where TMiddleware : IMiddleware,new() { - base.AddMiddleware(middlewareType); + + var middleware = new TMiddleware(); + if (middleware==null){ + + } + configure?.Invoke(middleware); + Middleware.Add(middleware); + return this; } @@ -50,24 +45,16 @@ public IPipeline Add(Type middlewareType) /// The input that will be provided to all middleware. public void Execute(TParameter parameter) { - if (MiddlewareTypes.Count == 0) - return; - - int index = 0; - Action action = null; - action = (param) => - { - var type = MiddlewareTypes[index]; - var middleware = (IMiddleware)MiddlewareResolver.Resolve(type); - - index++; - if (index == MiddlewareTypes.Count) - action = (p) => { }; - - middleware.Run(param, action); - }; - action(parameter); + Do(parameter,Middleware.GetEnumerator()); + return; + + void Do(TParameter _param,IEnumerator> e){ + if(!e.MoveNext()) return; + e.Current.Run(_param,p=>{ + Do(p,e); + }); + } } } } \ No newline at end of file