让 .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 ...
随机推荐
- 建议5:防止switch贯穿
switch语句,除非明确地中断流程,否则每次条件判断后都贯穿到下一个case条件.例如 switch(expression){ case label1: statementList1 case la ...
- 关于Idea中不能使用Scanner在console
遇到了麻烦,在Idea中使用@Test运行程序时,scanner在控制台无法输入,然后来回折腾... 创建了一个新的类里面含有main方法,可以完美运行scanner: 重新回来,发现还是不行, 创建 ...
- 手动生成WebService代理类
方式一: 手动生成WebService代理类需要把一句生成语句,如 wsdl.exe /l:cs /out:D:/ProxyServices.cs http://localhost/WebServic ...
- linux入门系列18--Web服务之Apache服务1
前面系列文章讲解了Linux下通过文件传输.文件共享.邮件系统来分享和获取资源,本文讲解网络资源获取和共享的另外一种形式,通过Apache服务程序来提供Web服务. 本文先讲解目前主流的Web服务程序 ...
- Java基础语法(2)-变量
title: Java基础语法(2)-变量 blog: CSDN data: Java学习路线及视频 1.什么是变量? 变量的概念 内存中的一个存储区域 该区域的数据可以在同一类型范围内不断变化 变量 ...
- ORM常用字段及方式
创建小型数据库 模型层 ORM常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为id的列. Integer ...
- 201771010103 陈亚茹 《面向对象程序设计(java)》第一周学习总结
本人学号<面向对象程序设计(java)>第一周学习总结 第一部分:课程准备部分 填写课程学习 平台注册账号, 平台名称 注册账号 博客园:www.cnblogs.com https://w ...
- Contest 141
2019-06-16 14:35:52 1089. Duplicate Zeros - Easy 问题描述: 问题求解: 很显然的可以使用O(n), O(n)的解法.主要问题在于如何在O(1)空间复杂 ...
- Hive常用的10个系统函数及作用
聚合函数 函数处理的数据粒度为多条记录. sum()—求和 count()—求数据量 avg()—求平均直 distinct—求不同值数 min—求最小值 max—求最人值 分析函数 Analytic ...
- 理解BERT:一个突破性NLP框架的综合指南
概述 Google的BERT改变了自然语言处理(NLP)的格局 了解BERT是什么,它如何工作以及产生的影响等 我们还将在Python中实现BERT,为你提供动手学习的经验 BERT简介 想象一下-- ...