让 .NET 轻松构建中间件模式代码
让 .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
让 .NET 轻松构建中间件模式代码的更多相关文章
- 让 .NET 轻松构建中间件模式代码(二)
让 .NET 轻松构建中间件模式代码(二)--- 支持管道的中断和分支 Intro 上次实现了一个基本的构建中间件模式的中间件构建器,现在来丰富一下功能,让它支持中断和分支,分别对应 asp.net ...
- Java工作流引擎-中间件模式代码集成
关键词:工作流快速开发平台 工作流流设计 业务流程管理 asp.net 开源工作流 bpm工作流系统 java工作流主流框架 自定义工作流引擎 表单设计器 流程设计器 前端代码集成步骤 ...
- Java设计模式之《构建者模式》及应用场景
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6553374.html 构建者模式,又称建造者模式,将一部负责对象的构建分为许多小对象的构建 ...
- ASP.NET Core 1.0中的管道-中间件模式
ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middleware)的方式注册在管道中.显而易见这样的设计非常松耦合 ...
- Core 1.0中的管道-中间件模式
ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...
- 掌握这个Python小技巧,轻松构建cytoscape导入文件
今天小编和大家分享如何借助Python脚本轻松构建cytoscape导入文件.Cytoscape是一个非常适合展示各种相互作用关系的可视化软件. 具体来说就是可以用于蛋白互作网络的展示,miRNA与蛋 ...
- 深入探索Java设计模式之构建器模式(五)
抽丝剥茧 细说架构那些事——[优锐课] 简单的程序不需要大量的设计过程,因为它们只关注有限的解决方案,仅使用几个类.大型程序专注于广泛的设计,该设计比好的设计范例的任何其他属性都更能利用可重用性.宏伟 ...
- 腾讯大牛半年心血高级编程PDF,帮你轻松构建企业级Web应用
毫无疑问,Java 是这些年来最流行的编程语言之一.它无处不在一计算机. 手机.网站以及各种嵌入式设备中都存在着大量的Java 应用程序,而其中应用最为广泛的应该就是Java EE Web应用程序(以 ...
- IE浏览器的兼容模式代码细节解读
兼容性对于网页设计师来说非常重要.虽然最好是建立一个完全不需依赖任何网页浏览器特性或功能的网站,但是有时候这是不可能实现的.而文件兼容模式能将网页限制在某个特定版本的IE中.可以使用 X-UA-Com ...
随机推荐
- $props, $attrs,$listeners的具体使用例子
我在这使用属性重新render饿了么ui的tree: <el-tree ref="tree" icon-class="fa fa-caret-right" ...
- PDF顯示插件
1. ie瀏覽器適用<object id="pdf_panel" class="pdf-panel" classid="clsid:CA8A97 ...
- ERP系统定价模型及费用组成
很多人选择ERP系统的时候最关心的就是费用问题,因为很多中小企业资金都是比较缺乏的,如果需要使用大量的金钱来购买ERP系统这是不现实的.你知道ERP系统的定价模型有哪些吗?你知道影响ERP系统价格的因 ...
- Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan (解读人:王茹凯)
文献名:Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan(平分GlcNAc是N-聚糖末端修饰的 ...
- 关于git 远程仓库账户密码错误的问题
主要是电脑凭证把第一次输入的账户密码记录了下来,在控制面板->用户账户->凭据管理器里, 选择windows凭证, 你会找到git:凭据,直接删掉或者更改都可以! 对应的Git的凭证,删除 ...
- Servlet(一)----快速入门
## Servlet:server applet * 概念:运行在服务端的小程序 * servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则. * 将来我们自定义一 ...
- 洛谷 P5176 公约数 题解
原题链接 我天哪 大大的庆祝一下: 数论黑题 \(T1\) 达成! 激动地不行 记住套路:乱推 \(\gcd\),欧拉筛模板,然后乱换元,乱换式子,完了整除分块,欧拉筛和前缀和就解决了! \[\sum ...
- Python第三章-输入输出和运算符
输入输出和运算符 一.输入和输出 1.1 输出 `print()`函数用来向终端输出数据(其实也可以向文件输出数据,后面再讲) 可以传递多个参数,则输出的时候 python 会把多个参数的值用空格隔开 ...
- 正则表达式(R&Python)
regular expression 1.R,strongly recommend this blog The table_info examples are following: du_mtime_ ...
- Tensorflow系列专题(四):神经网络篇之前馈神经网络综述
目录: 神经网络前言 神经网络 感知机模型 多层神经网络 激活函数 Logistic函数 Tanh函数 ReLu函数 损失函数和输出单元 损失函数的选择 均方误差损失函数 交叉熵损失函数 输出单元的选 ...