在 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; } }