首页 > Web开发 > 详细

让 .NET 轻松构建中间件模式代码(二)

时间:2020-04-16 10:15:42      阅读:57      评论:0      收藏:0      [点我收藏+]
原文:让 .NET 轻松构建中间件模式代码(二)

让 .NET 轻松构建中间件模式代码(二)--- 支持管道的中断和分支

Intro#

上次实现了一个基本的构建中间件模式的中间件构建器,现在来丰富一下功能,让它支持中断和分支,分别对应 asp.net core 中的 applicationBuilder.RunapplicationBuilder.MapWhen

实现管道中断#

实现中间件的中断其实很简单,通过上一次的分析我们已经知道,中间件每一个部分其实是一个上下文和 next 的委托,只需要忽略 next,不执行 next 就可以了,就可以中断后面中间件的执行。

定义一个 Run 扩展方法来实现方便的实现中间件中断:

Copy
public static IPipelineBuilder<TContext> Run<TContext>(this IPipelineBuilder<TContext> builder, Action<TContext> handler) { return builder.Use(_ => handler); } public static IAsyncPipelineBuilder<TContext> Run<TContext>(this IAsyncPipelineBuilder<TContext> builder, Func<TContext, Task> handler) { return builder.Use(_ => handler); }

实现分支#

分支的实现主要是参考 asp.net core 里 applicationBuilder.Map/applicationBuilder.MapWhen 实现分支路由的做法,在 asp.net core 里,MapWhen 是一个扩展方法,其实现是一个 MapWhenMiddleware,有兴趣可以看 asp.net core 的源码。

实现原理也挺简单的,其实就是满足分支的条件时创建一个全新的中间件管道,当满足条件的时候就就执行这个分支中间件管道,否则就跳过这个分支进入下一个中间件。

首先在 PipelineBuilder 的接口定义中增加了一个 New 方法用来创建一个全新的中间件管道,定义如下:

Copy
public interface IPipelineBuilder<TContext> { IPipelineBuilder<TContext> Use(Func<Action<TContext>, Action<TContext>> middleware); Action<TContext> Build(); IPipelineBuilder<TContext> New(); } // public interface IAsyncPipelineBuilder<TContext> { IAsyncPipelineBuilder<TContext> Use(Func<Func<TContext, Task>, Func<TContext, Task>> middleware); Func<TContext, Task> Build(); IAsyncPipelineBuilder<TContext> New(); }

实现就是直接创建了一个新的 PipelineBuilder<TContext> 对象,示例如下:

Copy
internal class PipelineBuilder<TContext> : IPipelineBuilder<TContext> { private readonly Action<TContext> _completeFunc; private readonly List<Func<Action<TContext>, Action<TContext>>> _pipelines = new List<Func<Action<TContext>, Action<TContext>>>(); public PipelineBuilder(Action<TContext> completeFunc) { _completeFunc = completeFunc; } public IPipelineBuilder<TContext> Use(Func<Action<TContext>, Action<TContext>> middleware) { _pipelines.Add(middleware); return this; } public Action<TContext> Build() { var request = _completeFunc; for (var i = _pipelines.Count - 1; i >= 0; i--) { var pipeline = _pipelines[i]; request = pipeline(request); } return request; } public IPipelineBuilder<TContext> New() => new PipelineBuilder<TContext>(_completeFunc); }

异步的和同步类似,这里就不再赘述,有疑问可以直接看文末的源码链接

接着就可以定义我们的分支扩展了

Copy
public static IPipelineBuilder<TContext> When<TContext>(this IPipelineBuilder<TContext> builder, Func<TContext, bool> predict, Action<IPipelineBuilder<TContext>> configureAction) { return builder.Use((context, next) => { if (predict.Invoke(context)) { var branchPipelineBuilder = builder.New(); configureAction(branchPipelineBuilder); var branchPipeline = branchPipelineBuilder.Build(); branchPipeline.Invoke(context); } else { next(); } }); }

使用示例#

我们可以使用分支和中断来改造一下昨天的示例,改造完的示例如下:

Copy
var requestContext = new RequestContext() { RequesterName = "Kangkang", Hour = 12, }; var builder = PipelineBuilder.Create<RequestContext>(context => { Console.WriteLine($"{context.RequesterName} {context.Hour}h apply failed"); }) .When(context => context.Hour <= 2, pipeline => { pipeline.Use((context, next) => { Console.WriteLine("This should be invoked"); next(); }); pipeline.Run(context => Console.WriteLine("pass 1")); pipeline.Use((context, next) => { Console.WriteLine("This should not be invoked"); next(); Console.WriteLine("will this invoke?"); }); }) .When(context => context.Hour <= 4, pipeline => { pipeline.Run(context => Console.WriteLine("pass 2")); }) .When(context => context.Hour <= 6, pipeline => { pipeline.Run(context => Console.WriteLine("pass 3")); }) ; var requestPipeline = builder.Build(); Console.WriteLine(); foreach (var i in Enumerable.Range(1, 8)) { Console.WriteLine($"--------- h:{i} apply Pipeline------------------"); requestContext.Hour = i; requestPipeline.Invoke(requestContext); Console.WriteLine("----------------------------"); }

输出结果如下:

技术分享图片

看输出结果我们可以看到 Run 后面注册的中间件是不会执行的,Run 前面注册的中间件正常执行

然后定义的 When 分支也是正确执行的~~

Reference#

让 .NET 轻松构建中间件模式代码(二)

原文:https://www.cnblogs.com/lonelyxmas/p/12710459.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!