让 .NET 轻松构建中间件模式代码
程序员文章站
2022-04-14 16:02:35
让 .NET 轻松构建中间件模式代码 Intro 在 asp.net core 中中间件的设计令人叹为观止,如此高大上的设计何不集成到自己的代码里呢。 于是就有了封装了一个简单通用的中间件模板的想法,以后有需要的时候就可以拿来即用。 接口定义 这里按执行的委托是同步还是异步分为了同步和异步两种构建方 ......
让 .net 轻松构建中间件模式代码
intro
在 asp.net core 中中间件的设计令人叹为观止,如此高大上的设计何不集成到自己的代码里呢。
于是就有了封装了一个简单通用的中间件模板的想法,以后有需要的时候就可以拿来即用。
接口定义
这里按执行的委托是同步还是异步分为了同步和异步两种构建方法
//没有返回值的同步中间件构建器 public interface ipipelinebuilder<tcontext> { ipipelinebuilder<tcontext> use(func<action<tcontext>, action<tcontext>> middleware); action<tcontext> build(); } // 异步中间件构建器 public interface iasyncpipelinebuilder<tcontext> { iasyncpipelinebuilder<tcontext> use(func<func<tcontext, task>, func<tcontext, task>> middleware); func<tcontext, task> build(); }
为了方便使用,定义一下扩展方法,使得可以像 asp.net core 中 app.use(fun<httpcontext, func<task>, task>)
一样比较方便的使用,扩展方法定义如下:
public static ipipelinebuilder<tcontext> use<tcontext>(this ipipelinebuilder<tcontext> builder, action<tcontext, action> action) { return builder.use(next => context => { action(context, () => next(context)); }); } public static iasyncpipelinebuilder<tcontext> use<tcontext>(this iasyncpipelinebuilder<tcontext> builder, func<tcontext, func<task>, task> func) { return builder.use(next => context => { return func(context, () => next(context)); }); }
为了方便创建对应的 pipelinebuilder
,这里定义了两个方法:
使用 create
方法就可以创建一个 ipipelinebuilder
,使用 createasync
就可以创建一个 iasyncpipelinebuilder
public class pipelinebuilder { public static ipipelinebuilder<tcontext> create<tcontext>(action<tcontext> completeaction) { return new pipelinebuilder<tcontext>(completeaction); } public static iasyncpipelinebuilder<tcontext> createasync<tcontext>(func<tcontext, task> completefunc) { return new asyncpipelinebuilder<tcontext>(completefunc); } }
使用示例
来看一个使用示例,这里的示例修改自设计模式里的责任链模式的一个示例,废话不说,来看代码:
这是一个请假的示例,不同的请假时间交由不同的审批主管进行审批,最后模拟了从请假1小时到请假8小时的申请处理情况
private class requestcontext { public string requestername { get; set; } public int hour { get; set; } } public static void test() { var requestcontext = new requestcontext() { requestername = "kangkang", hour = 12, }; var builder = pipelinebuilder.create<requestcontext>(context => { console.writeline($"{context.requestername} {context.hour}h apply failed"); }) .use((context, next) => { if (context.hour <= 2) { console.writeline("pass 1"); } else { next(); } }) .use((context, next) => { if (context.hour <= 4) { console.writeline("pass 2"); } else { next(); } }) .use((context, next) => { if (context.hour <= 6) { console.writeline("pass 3"); } else { next(); } }) ; var requestpipeline = builder.build(); foreach (var i in enumerable.range(1, 8)) { console.writeline(); console.writeline($"--------- h:{i} apply pipeline------------------"); requestcontext.hour = i; requestpipeline.invoke(requestcontext); console.writeline("----------------------------"); console.writeline(); } } public static async task asyncpipelinebuildertest() { var requestcontext = new requestcontext() { requestername = "michael", hour = 12, }; var builder = pipelinebuilder.createasync<requestcontext>(context => { console.writeline($"{context.requestername} {context.hour}h apply failed"); return task.completedtask; }) .use(async (context, next) => { if (context.hour <= 2) { console.writeline("pass 1"); } else { await next(); } }) .use(async (context, next) => { if (context.hour <= 4) { console.writeline("pass 2"); } else { await next(); } }) .use(async (context, next) => { if (context.hour <= 6) { console.writeline("pass 3"); } else { await next(); } }) ; var requestpipeline = builder.build(); foreach (var i in enumerable.range(1, 8)) { console.writeline($"--------- h:{i} apply asyncpipeline------------------"); requestcontext.hour = i; await requestpipeline.invoke(requestcontext); console.writeline("----------------------------"); } }
运行效果:
实现代码
internal class pipelinebuilder<tcontext> : ipipelinebuilder<tcontext> { private readonly action<tcontext> _completefunc; private readonly ilist<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; foreach (var pipeline in _pipelines.reverse()) { request = pipeline(request); } return request; } } internal class asyncpipelinebuilder<tcontext> : iasyncpipelinebuilder<tcontext> { private readonly func<tcontext, task> _completefunc; private readonly ilist<func<func<tcontext, task>, func<tcontext, task>>> _pipelines = new list<func<func<tcontext, task>, func<tcontext, task>>>(); public asyncpipelinebuilder(func<tcontext, task> completefunc) { _completefunc = completefunc; } public iasyncpipelinebuilder<tcontext> use(func<func<tcontext, task>, func<tcontext, task>> middleware) { _pipelines.add(middleware); return this; } public func<tcontext, task> build() { var request = _completefunc; foreach (var pipeline in _pipelines.reverse()) { request = pipeline(request); } return request; } }
reference
- https://github.com/weihanli/weihanli.common/blob/dev/samples/dotnetcoresample/pipelinetest.cs
- https://github.com/weihanli/weihanli.common/blob/dev/src/weihanli.common/helpers/pipelines/pipelinebuilder.cs
- https://github.com/dotnet/aspnetcore/blob/master/src/http/http/src/builder/applicationbuilder.cs
上一篇: css3实现鼠标移入图片动效
下一篇: 一个简单的交叉报表