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); }
/// <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> >()); }
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); } }; })); }
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); }
public static IPipelineBuilder <TContext> Use <TContext>(this IPipelineBuilder <TContext> builder, Action <TContext, Action <TContext> > action) { return(builder.Use(next => context => { action(context, next); })); }
/// <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(); });
/// <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); }; })); }
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! }
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)); } );
/// <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); } )); }
/// <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)); }; })); }
/// <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>();
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); }; })); }
/// <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); })); }
/// <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); } })); }
/// <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); } )); }
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)); })); }
/// <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); } })); }
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))); }
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); }; })); }
/// <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); } }; })); }
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)))); }
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(); } }); }