public async Task Will_execute_each_mixed_middleware_layer_exactly_once(
            [Random(
                 0,
                 10,
                 5,
                 Distinct = false
                 )]
            int segmentCount,
            [Random(
                 -10000,
                 10000,
                 5,
                 Distinct = true
                 )]
            int input
            )
        {
            IPipelineBuilder <int, int, int, int> builder = Pipeline.Of <int, int>();

            for (var i = 0; i < segmentCount; i++)
            {
                builder = i % 3 == 0
                    ? builder.Use((x, next) => next(x + 1))
                    : builder.Use <AddOne>();
            }

            var calculator = builder.OutputTo(x => x)
                             .BuildPipeline(Resolver.Resolve);

            var expectedResult = input + segmentCount;
            var result         = await calculator(input);

            Assert.AreEqual(expectedResult, result);
        }
Ejemplo n.º 2
0
        /// <summary>
        ///     Adds a Polly IAsyncPolicy as middleware.
        /// </summary>
        /// <param name="pipelineBuilder">The pipeline builder</param>
        /// <param name="options">Option configuration</param>
        /// <typeparam name="T">The underlying type for the pipeline</typeparam>
        /// <returns>The modified pipeline builder</returns>
        public static IPipelineBuilder <T> UsePolly <T>(this IPipelineBuilder <T> pipelineBuilder, Action <PollyMiddlewareOptions <T> > options)
        {
            pipelineBuilder.Services.TryAddSingleton <PollyMiddleware <T> >();
            pipelineBuilder.Services.Configure(options);

            return(pipelineBuilder.Use <PollyMiddleware <T> >());
        }
Ejemplo n.º 3
0
        private static IPipelineBuilder <TService, TContext> UseMiddlewareInterface <TService, TContext>(IPipelineBuilder <TService, TContext> app, Type middlewareType)
            where TService : BaseDomainService
            where TContext : IRequestContext
        {
            return(app.Use(next =>
            {
                return async context =>
                {
                    IMiddlewareFactory <TContext> middlewareFactory = (IMiddlewareFactory <TContext>)context.RequestServices.GetService(typeof(IMiddlewareFactory <TContext>));
                    if (middlewareFactory == null)
                    {
                        // No middleware factory
                        throw new InvalidOperationException("UseMiddlewareNoMiddlewareFactory(typeof(IMiddlewareFactory))");
                    }

                    IMiddleware <TContext> middleware = middlewareFactory.Create(middlewareType);
                    if (middleware == null)
                    {
                        // The factory returned null, it's a broken implementation
                        throw new InvalidOperationException("UseMiddlewareUnableToCreateMiddleware(middlewareFactory.GetType(), middlewareType)");
                    }

                    try
                    {
                        await middleware.InvokeAsync(context, next);
                    }
                    finally
                    {
                        middlewareFactory.Release(middleware);
                    }
                };
            }));
        }
Ejemplo n.º 4
0
 protected override IPipelineBuilder <string, Command, Response, string> Configure(
     IPipelineBuilder <string, string, string, string> builder
     )
 => builder.Use <Command, Response>(
     async(request, next, ct) =>
 {
     var response = await next(
         new Command
     {
         Value = request
     },
         ct
         );
     return(response.Value);
 }
     )
 .Use <string, string>(
     async(request, next, ct) => new Response
 {
     Value = await next(request.Value, ct)
 }
     ).Use <Command, Response>(
     async(request, next, ct) =>
 {
     var response = await next(
         new Command
     {
         Value = request
     },
         ct
         );
     return(response.Value);
 }
     );
 public static void UseMiddleware(this IPipelineBuilder @this, IMiddleware middleware)
 {
     if (middleware == null)
     {
         throw new ArgumentNullException(nameof(middleware));
     }
     @this.Use(middleware.Invoke);
 }
Ejemplo n.º 6
0
 public static IPipelineBuilder <TContext> Use <TContext>(this IPipelineBuilder <TContext> builder, Action <TContext, Action <TContext> > action)
 {
     return(builder.Use(next =>
                        context =>
     {
         action(context, next);
     }));
 }
Ejemplo n.º 7
0
        /// <summary>
        /// Adds to the pipeline a middleware used to interpret effects generated by the given message payload handler
        /// </summary>
        /// <param name="pipelineBuilder">The pipeline builder.</param>
        /// <param name="messageHandler">A handler that receives the message payload and returns an effect.</param>
        /// <returns>The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.</returns>
        public static IPipelineBuilder <MessagingContext> UseEffectMiddleware(this IPipelineBuilder <MessagingContext> pipelineBuilder, Func <object, Effect <Unit> > messageHandler)
        => pipelineBuilder.Use(async(context, token, next) =>
        {
            var interpreter = context.Services.GetRequiredService <IInterpreter>();
            var effect      = messageHandler(context.MessagingEnvelope.Payload);

            await interpreter.Interpret(effect, token);
            await next.Invoke();
        });
        /// <summary>
        /// Adds to the pipeline a middleware used to interpret effects generated by the given message payload handler
        /// </summary>
        /// <param name="pipelineBuilder">The pipeline builder.</param>
        /// <param name="messageHandler">A handler that receives the message payload and returns an effect.</param>
        /// <returns>The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.</returns>
        public static IPipelineBuilder <MessagingEnvelope> UseEffectMiddleware(this IPipelineBuilder <MessagingEnvelope> pipelineBuilder, Func <object, IEffect> messageHandler)
        => pipelineBuilder.Use(async(envelope, token, next) =>
        {
            var interpreter = pipelineBuilder.ServiceProvider.GetRequiredService <IInterpreter>();
            var effect      = messageHandler(envelope.Payload);

            await interpreter.Interpret(effect, token);
            await next.Invoke();
        });
Ejemplo n.º 9
0
        /// <summary>
        /// Adds a middleware type to the application's request pipeline.
        /// </summary>
        /// <param name="app">The <see cref="IApplicationBuilder"/> instance.</param>
        /// <param name="middleware">The middleware type.</param>
        /// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
        /// <returns>The <see cref="IApplicationBuilder"/> instance.</returns>
        public static IPipelineBuilder UseMiddleware(this IPipelineBuilder app, Type middleware, params object[] args)
        {
            var applicationServices = app.ApplicationServices;

            return(app.Use(next =>
            {
                var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                var invokeMethods = methods.Where(m =>
                                                  string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal)
                                                  ).ToArray();

                if (invokeMethods.Length > 1)
                {
                    throw new InvalidOperationException($"Found multiple InvokeAsync methods on {middleware}");
                }

                if (invokeMethods.Length == 0)
                {
                    throw new InvalidOperationException($"No InvokeAsync method found on {middleware}");
                }

                var methodinfo = invokeMethods[0];
                if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType))
                {
                    throw new InvalidOperationException($"InvokeAsync method on {middleware} does not return a Task");
                }

                var parameters = methodinfo.GetParameters();
                if (parameters.Length == 0 || parameters[0].ParameterType != typeof(MessageContext))
                {
                    throw new InvalidOperationException($"First parameter on {middleware}.InvokeAsync must be a {nameof(MessageContext)}");
                }

                var ctorArgs = new object[args.Length + 1];
                ctorArgs[0] = next;
                Array.Copy(args, 0, ctorArgs, 1, args.Length);
                var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
                if (parameters.Length == 1)
                {
                    return (MessageDelegate)methodinfo.CreateDelegate(typeof(MessageDelegate), instance);
                }

                var factory = Compile <object>(methodinfo, parameters);

                return context =>
                {
                    var serviceProvider = context.MessageServices ?? applicationServices;
                    if (serviceProvider == null)
                    {
                        throw new InvalidOperationException($"'{nameof(IServiceProvider)}' is not available.");
                    }

                    return factory(instance, context, serviceProvider);
                };
            }));
        }
Ejemplo n.º 10
0
        public void ConfigurePipeline(IPipelineBuilder pipe)
        {
            // Middleware type example - terminal if the message is empty
            pipe.UseMiddleware <ExampleMiddleware>();

            // Raw delegate examples below, but recommendation is Middleware classes
            // since they support dependency injection

            // wrap the next components with this bit of middleware:
            pipe.Use(WrappingExample);

            // Optional terminal example - passes along if a condition passes
            pipe.Use(FilteringExample);

            // Run adds terminal middleware - won't pass on the context any further
            pipe.Run(TerminalExample);

            // Any middleware here (after the Run) will never be invoked!
        }
Ejemplo n.º 11
0
 protected override IPipelineBuilder <Command, Command, Response, Response> Configure(
     IPipelineBuilder <Command, Command, Response, Response> builder
     )
 => builder.Use(
     (request, next, ct) =>
 {
     request.Value = "";
     return(next(request, ct));
 }
     );
Ejemplo n.º 12
0
 /// <summary>
 /// Adds a middleware of type <typeparamref name="TMiddleware"/> the pipeline.
 /// </summary>
 /// <typeparam name="TMiddleware">The type of the middleware.</typeparam>
 /// <typeparam name="T">The type of data/context processed in the pipeline.</typeparam>
 /// <param name="pipelineBuilder">The pipeline builder.</param>
 /// <returns>
 /// The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.
 /// </returns>
 public static IPipelineBuilder <T> UseMiddleware <TMiddleware, T>(this IPipelineBuilder <T> pipelineBuilder) where TMiddleware : IPipelineMiddleware <T>
 {
     return(pipelineBuilder.Use(
                (data, cancellationToken, next) =>
     {
         var instance = (IPipelineMiddleware <T>)ActivatorUtilities.CreateInstance(pipelineBuilder.ServiceProvider, typeof(TMiddleware));
         return instance.Invoke(data, cancellationToken, next);
     }
                ));
 }
Ejemplo n.º 13
0
 /// <summary>
 ///     Adds a middleware step into the pipeline
 /// </summary>
 public static IPipelineBuilder <T> Use <T>(this IPipelineBuilder <T> builder, Func <Message <T>, Func <Task>, Task> middleware)
 {
     return(builder.Use(next =>
     {
         return (message, cancellationToken, messageContext) =>
         {
             return middleware(message, () => next(message, cancellationToken, messageContext));
         };
     }));
 }
Ejemplo n.º 14
0
 /// <summary>
 /// Adds the a middleware that is defined inline to the pipeline.
 /// </summary>
 /// <typeparam name="T">The type of data/context processed in the pipeline.</typeparam>
 /// <param name="pipelineBuilder">The pipeline builder.</param>
 /// <param name="middleware">The middleware.</param>
 /// <returns>
 /// The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.
 /// </returns>
 public static IPipelineBuilder <T> Use <T>(this IPipelineBuilder <T> pipelineBuilder, Func <T, CancellationToken, Func <Task>, Task> middleware)
 {
     return(pipelineBuilder.Use(next =>
     {
         return (data, token) =>
         {
             Func <Task> simpleNext = () => next(data, token);
             return middleware(data, token, simpleNext);
         };
     }));
 }
 protected override IPipelineBuilder <string, Command, Response, string> Configure(
     IPipelineBuilder <string, string, string, string> builder
     )
 => builder.Use <StringToCommandAdapter, Command, Response>()
 .Use <string, string>(
     async(request, next, ct) => new Response
 {
     Value = await next(request.Value, ct)
 }
     )
 .Use <StringToCommandAdapter, Command, Response>();
Ejemplo n.º 16
0
 public static IPipelineBuilder <TService, TContext> Use <TService, TContext>(this IPipelineBuilder <TService, TContext> app, Func <TContext, Func <Task>, Task> middleware)
     where TService : BaseDomainService
     where TContext : IRequestContext
 {
     return(app.Use(next =>
     {
         return context =>
         {
             Func <Task> simpleNext = () => next(context);
             return middleware(context, simpleNext);
         };
     }));
 }
Ejemplo n.º 17
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="middlewareType"></param>
        /// <param name="args"></param>
        public static IPipelineBuilder <TPipelineContext> UseMiddleware <TPipelineContext>(this IPipelineBuilder <TPipelineContext> builder, Type middlewareType, params object[] args)
        {
            Check.NotNull(builder, nameof(builder));
            Check.NotNull(middlewareType, nameof(middlewareType));
            builder.Use(next =>
            {
                var methods = middlewareType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(m => m.Name.IsIn("Invoke", "InvokeAsync")).ToArray();
                if (methods.Length > 1)
                {
                    throw new InvalidOperationException();
                }

                if (methods.Length == 0)
                {
                    throw new InvalidOperationException();
                }
                var methodinfo = methods[0];
                if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType))
                {
                    throw new InvalidOperationException();
                }
                var parameters = methodinfo.GetParameters();
                if (parameters.Length == 0 || parameters[0].ParameterType != typeof(TPipelineContext))
                {
                    throw new InvalidOperationException();
                }

                var ctorArgs = new object[args.Length + 1];
                ctorArgs[0]  = next;
                Array.Copy(args, 0, ctorArgs, 1, args.Length);
                var instance = ActivatorUtilities.CreateInstance(builder.ApplicationServices, middlewareType, ctorArgs);
                if (parameters.Length == 1)
                {
                    return((PipelineRequestDelegate <TPipelineContext>)methodinfo.CreateDelegate(typeof(PipelineRequestDelegate <TPipelineContext>), instance));
                }

                var factory = Compile <object, TPipelineContext>(methodinfo, parameters);

                return(context =>
                {
                    var serviceProvider = builder.ApplicationServices;
                    if (serviceProvider == null)
                    {
                        throw new InvalidOperationException();
                    }

                    return factory(instance, context, serviceProvider);
                });
            });
            return(builder);
        }
        /// <summary>
        /// Adds a middleware func to be executed in pipeline.
        /// </summary>
        /// <param name="builder">Pipeline builder.</param>
        /// <param name="middleware">The middleware as func to be executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="middleware"/> is null.</exception>
        /// <returns>A reference to the builder after the operation has completed.</returns>
        public static IPipelineBuilder <TParameter> Use <TParameter>(
            this IPipelineBuilder <TParameter> builder,
            Func <MiddlewareDelegate <TParameter>, MiddlewareDelegate <TParameter> > middleware)
        {
            if (middleware == null)
            {
                throw new ArgumentNullException(nameof(middleware));
            }

            return(builder.Use((_, next) => (context, cancellationToke) =>
            {
                return middleware((c, _) => next(c))(context, cancellationToke);
            }));
        }
Ejemplo n.º 19
0
 /// <summary>
 /// 条件中间件
 /// </summary>
 /// <typeparam name="TContext"></typeparam>
 /// <param name="builder"></param>
 /// <param name="predicate"></param>
 /// <param name="handler"></param>
 /// <returns></returns>
 public static IPipelineBuilder <TContext> When <TContext>(this IPipelineBuilder <TContext> builder, Func <TContext, bool> predicate, InvokeDelegate <TContext> handler)
 {
     return(builder.Use(next => async context =>
     {
         if (predicate.Invoke(context) == true)
         {
             await handler.Invoke(context);
         }
         else
         {
             await next(context);
         }
     }));
 }
Ejemplo n.º 20
0
 /// <summary>
 /// Adds a middleware of type <typeparamref name="TMiddleware"/> the pipeline.
 /// </summary>
 /// <typeparam name="TMiddleware">The type of the middleware.</typeparam>
 /// <typeparam name="TContext">The type of data/context processed in the pipeline.</typeparam>
 /// <param name="pipelineBuilder">The pipeline builder.</param>
 /// <returns>
 /// The pipeline builder for further configuring the pipeline. It is used used in the fluent configuration API.
 /// </returns>
 public static IPipelineBuilder <TContext> UseMiddleware <TMiddleware, TContext>(
     this IPipelineBuilder <TContext> pipelineBuilder)
     where TMiddleware : IPipelineMiddleware <TContext>
     where TContext : IPipelineContext
 {
     return(pipelineBuilder.Use(
                (context, cancellationToken, next) =>
     {
         var instance =
             (IPipelineMiddleware <TContext>)ActivatorUtilities.CreateInstance(context.Services,
                                                                               typeof(TMiddleware));
         return instance.Invoke(context, cancellationToken, next);
     }
                ));
 }
Ejemplo n.º 21
0
        public static void Run <TService, TContext>(this IPipelineBuilder <TService, TContext> app, RequestDelegate <TContext> handler)
            where TService : BaseDomainService
            where TContext : IRequestContext
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            app.Use(_ => handler);
        }
        /// <summary>
        /// Adds a middleware func to be executed in pipeline.
        /// </summary>
        /// <param name="builder">Pipeline builder.</param>
        /// <param name="middleware">The middleware as func to be executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="middleware"/> is null.</exception>
        /// <returns>A reference to the builder after the operation has completed.</returns>
        public static IPipelineBuilder <TParameter> Use <TParameter>(
            this IPipelineBuilder <TParameter> builder,
            Func <TParameter, Func <Task>, Task> middleware
            )
            where TParameter : class
        {
            if (middleware == null)
            {
                throw new ArgumentNullException(nameof(middleware));
            }

            return(builder.Use((_, next) => (context, cancellationToken) =>
            {
                return middleware(context, () => next(context, cancellationToken));
            }));
        }
Ejemplo n.º 23
0
 /// <summary>
 /// 条件中间件
 /// </summary>
 /// <typeparam name="TContext"></typeparam>
 /// <param name="builder"></param>
 /// <param name="predicate"></param>
 /// <param name="configureAction"></param>
 /// <returns></returns>
 public static IPipelineBuilder <TContext> When <TContext>(this IPipelineBuilder <TContext> builder, Func <TContext, bool> predicate, Action <IPipelineBuilder <TContext> > configureAction)
 {
     return(builder.Use(next => async context =>
     {
         if (predicate.Invoke(context) == true)
         {
             var branchBuilder = builder.New();
             configureAction(branchBuilder);
             await branchBuilder.Build().Invoke(context);
         }
         else
         {
             await next(context);
         }
     }));
 }
Ejemplo n.º 24
0
        public static IPipelineBuilder <TRequest, TNextRequest, TNextResponse, TResponse> Use <TRequest, TNextRequest, TNextResponse, TResponse>(
            this IPipelineBuilder <TRequest, TNextRequest, TNextResponse, TResponse> segment,
            Func <TNextRequest, Process <TNextRequest, TNextResponse>, Task <TNextResponse> > decorator
            )
        {
            if (segment is null)
            {
                throw new ArgumentNullException(nameof(segment));
            }

            if (decorator is null)
            {
                throw new ArgumentNullException(nameof(decorator));
            }

            return(segment.Use((request, next, ct) => decorator(request, next)));
        }
Ejemplo n.º 25
0
        public static IPipelineBuilder <SomeContext> UseSubdomain1Pipeline(
            this IPipelineBuilder <SomeContext> pipelineBuilder
            )
        {
            return(pipelineBuilder.Use((sp, next) =>
            {
                return async(ctx, cancellationToken) =>
                {
                    if (ctx.Response.Type == SubDomainType.Subdomain1)
                    {
                        await BuildPipeline(sp).ExecuteAsync(ctx, cancellationToken);
                    }

                    await next(ctx, cancellationToken);
                };
            }));
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Conditionally creates a branch in the request pipeline that is rejoined to the main pipeline.
        /// </summary>
        /// <param name="app"></param>
        /// <param name="predicate">Invoked with the request environment to determine if the branch should be taken</param>
        /// <param name="configuration">Configures a branch to take</param>
        /// <returns></returns>
        public static IPipelineBuilder <TService, TContext> UseWhen <TService, TContext>(this IPipelineBuilder <TService, TContext> app, Predicate <TContext> predicate, Action <IPipelineBuilder <TService, TContext> > configuration)
            where TService : BaseDomainService
            where TContext : IRequestContext
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            // Create and configure the branch builder right away; otherwise,
            // we would end up running our branch after all the components
            // that were subsequently added to the main builder.
            PipelineBuilder <TService, TContext> branchBuilder = app.New();

            configuration(branchBuilder);

            return(app.Use(main =>
            {
                // This is called only when the main application builder
                // is built, not per request.
                branchBuilder.Run(main);
                RequestDelegate <TContext> branch = branchBuilder.Build();

                return context =>
                {
                    if (predicate(context))
                    {
                        return branch(context);
                    }
                    else
                    {
                        return main(context);
                    }
                };
            }));
        }
Ejemplo n.º 27
0
        public static IPipelineBuilder UseMiddleware(
            this IPipelineBuilder pipeline,
            [DynamicallyAccessedMembers(MiddlewareAccessibility)] Type middleware)
        {
            if (!typeof(IMiddleware).IsAssignableFrom(middleware))
            {
                throw new ArgumentException($"The middleware type must implement \"{typeof(IMiddleware)}\".");
            }

            var        methods      = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
            MethodInfo invokeMethod = null;

            foreach (var method in methods)
            {
                if (string.Equals(method.Name, InvokeAsyncMethodName, StringComparison.Ordinal))
                {
                    if (method == null)
                    {
                        throw new InvalidOperationException(InvokeAsyncMethodName);
                    }
                    invokeMethod = method;
                    break;
                }
            }

            if (invokeMethod is null)
            {
                throw new InvalidOperationException("No suitable method matched .");
            }

            if (!typeof(Task).IsAssignableFrom(invokeMethod.ReturnType))
            {
                throw new InvalidOperationException($"The method is not an awaitable method { nameof(Task) } !");
            }

            var parameters = invokeMethod.GetParameters();

            if (parameters.Length == 0 || parameters[0].ParameterType != typeof(BaseContext))
            {
                throw new InvalidOperationException($" The method parameter does not contain an { nameof(BaseContext) } type parameter !");
            }

            return(pipeline.Use(((IMiddleware)ActivatorMiddlewareResolver.Resolve(middleware))));
        }
Ejemplo n.º 28
0
        public static IPipelineBuilder <TContext> When <TContext>(this IPipelineBuilder <TContext> builder, Func <TContext, bool> predict, Action <IPipelineBuilder <TContext> > configureAction)
        {
            builder.Use((context, next) =>
            {
                if (predict.Invoke(context))
                {
                    var branchPipelineBuilder = builder.New();
                    configureAction(branchPipelineBuilder);
                    var branchPipeline = branchPipelineBuilder.Build();
                    branchPipeline.Invoke(context);
                }
                else
                {
                    next();
                }
            });

            return(builder);
        }
        /// <summary>
        /// Adds a middleware func to be executed in pipeline.
        /// </summary>
        /// <param name="builder">Pipeline builder.</param>
        /// <param name="middleware">The middleware as func to be executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="middleware"/> is null.</exception>
        /// <returns>A reference to the builder after the operation has completed.</returns>
        public static IPipelineBuilder <TParameter> Use <TParameter, TDep1>(
            this IPipelineBuilder <TParameter> builder,
            Func <TParameter, TDep1, Func <Task>, Task> middleware
            )
            where TParameter : class
            where TDep1 : notnull
        {
            if (middleware == null)
            {
                throw new ArgumentNullException(nameof(middleware));
            }

            return(builder.Use((sp, next) => (context, cancellationToken) =>
            {
                var dep1 = sp.GetRequiredService <TDep1>();

                return middleware(context, dep1, () => next(context, cancellationToken));
            }));
        }
        /// <summary>
        /// Ignore updates, that older than passed datetime.
        /// Now works only for messages and channel posts.
        /// Default is <see cref="DateTime.UtcNow"/>.
        /// <para></para>
        /// Invoke before middleware you want ignore.
        /// <para></para>
        /// Useful when you want to ignore messages sended when bot was disabled.
        /// </summary>
        public static void UseOldUpdatesIgnoring(this IPipelineBuilder @this, DateTime?dateTime = null)
        {
            var notNullableDateTime = dateTime ?? DateTime.UtcNow;

            @this.Use(async(ctx, next) =>
            {
                DateTime?updateTime = ctx.Update.ChannelPost?.Date
                                      ?? ctx.Update.Message?.Date;
                if (updateTime != null && updateTime < notNullableDateTime)
                {
                    //Ignoring...
                    ctx.ForceExit();
                }
                else
                {
                    await next();
                }
            });
        }