在 asp.net core 中中间件的设计使人叹为观止,如此高大上的设计何不集成到本身的代码里呢。git
因而就有了封装了一个简单通用的中间件模板的想法,之后有须要的时候就能够拿来即用。github
这里按执行的委托是同步仍是异步分为了同步和异步两种构建方法设计模式
//没有返回值的同步中间件构建器 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>)
同样比较方便的使用,扩展方法定义以下:app
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
,这里定义了两个方法:asp.net
使用 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); } }
来看一个使用示例,这里的示例修改自设计模式里的责任链模式的一个示例,废话不说,来看代码:async
这是一个请假的示例,不一样的请假时间交由不一样的审批主管进行审批,最后模拟了从请假1小时到请假8小时的申请处理状况ui
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("----------------------------"); } }
运行效果:this
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; } }