让 .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

让 .NET 轻松构建中间件模式代码的更多相关文章

  1. 让 .NET 轻松构建中间件模式代码(二)

    让 .NET 轻松构建中间件模式代码(二)--- 支持管道的中断和分支 Intro 上次实现了一个基本的构建中间件模式的中间件构建器,现在来丰富一下功能,让它支持中断和分支,分别对应 asp.net ...

  2. Java工作流引擎-中间件模式代码集成

    关键词:工作流快速开发平台  工作流流设计  业务流程管理   asp.net 开源工作流  bpm工作流系统  java工作流主流框架  自定义工作流引擎 表单设计器  流程设计器 前端代码集成步骤 ...

  3. Java设计模式之《构建者模式》及应用场景

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6553374.html 构建者模式,又称建造者模式,将一部负责对象的构建分为许多小对象的构建 ...

  4. ASP.NET Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middleware)的方式注册在管道中.显而易见这样的设计非常松耦合 ...

  5. Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...

  6. 掌握这个Python小技巧,轻松构建cytoscape导入文件

    今天小编和大家分享如何借助Python脚本轻松构建cytoscape导入文件.Cytoscape是一个非常适合展示各种相互作用关系的可视化软件. 具体来说就是可以用于蛋白互作网络的展示,miRNA与蛋 ...

  7. 深入探索Java设计模式之构建器模式(五)

    抽丝剥茧 细说架构那些事——[优锐课] 简单的程序不需要大量的设计过程,因为它们只关注有限的解决方案,仅使用几个类.大型程序专注于广泛的设计,该设计比好的设计范例的任何其他属性都更能利用可重用性.宏伟 ...

  8. 腾讯大牛半年心血高级编程PDF,帮你轻松构建企业级Web应用

    毫无疑问,Java 是这些年来最流行的编程语言之一.它无处不在一计算机. 手机.网站以及各种嵌入式设备中都存在着大量的Java 应用程序,而其中应用最为广泛的应该就是Java EE Web应用程序(以 ...

  9. IE浏览器的兼容模式代码细节解读

    兼容性对于网页设计师来说非常重要.虽然最好是建立一个完全不需依赖任何网页浏览器特性或功能的网站,但是有时候这是不可能实现的.而文件兼容模式能将网页限制在某个特定版本的IE中.可以使用 X-UA-Com ...

随机推荐

  1. php导出为excel文件避免内存溢出

    轻松解决PHPExcel导出10W行超时和内存溢出问题   使用了一个轻量级的PHP的Excel操作库-PHP_XLSXWriter 10w行excel数据导出仅需要5.26秒,再也不用担心excel ...

  2. 【TIJ4】第四章全部习题

    第四章 没啥好说的...... 4.1 package ex0401; //[4.1]写一个程序打印从1到100的值 public class PrintOneToHundred { public s ...

  3. 【Weiss】【第03章】队列例程

    前几个例程还是相当简单的,把链表即时改了一下就是队列了. 还有想了一下,决定这种例程的代码放法是:先把测试代码默认折叠放在前面,然后把实现代码默认展开放在后面. 测试代码如下: #include &l ...

  4. layui radio 单选框 效果 显示不来 解决方法

    $("input[name=sex][value=女]").attr("checked", data.data.adminInfoEntity.adminInf ...

  5. 使用burp插件captcha-killer识别图片验证码

    0x01 开发背景 说起对存在验证码的登录表单进行爆破,大部分人都会想到PKav HTTP Fuzzer,这款工具在前些年确实给我们带来了不少便利.反观burp一直没有一个高度自定义通杀大部分图片验证 ...

  6. 洛谷 P3870 [TJOI2009]开关 题解

    原题链接 前置知识: 线段树的单点.区间的修改与查询. 一看,我们需要维护两个操作: 区间取反: 区间求和. (因为区间 \(1\) 的个数,就是区间的和) 典型的 线段树 . 如果你只会线段树的 区 ...

  7. Java并发编程(03):多线程并发访问,同步控制

    本文源码:GitHub·点这里 || GitEE·点这里 一.并发问题 多线程学习的时候,要面对的第一个复杂问题就是,并发模式下变量的访问,如果不理清楚内在流程和原因,经常会出现这样一个问题:线程处理 ...

  8. 计算几何-Minimum Area Rectangle II

    2020-02-10 21:02:13 问题描述: 问题求解: 本题由于可以暴力求解,所以不是特别难,主要是用来熟悉计算几何的一些知识点的. public double minAreaFreeRect ...

  9. 爬虫&Selenium&ChromeDriver

    一.Selenium selenium是什么 Selenium [1] 是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, ...

  10. Arcgis连接SQL Server提示试图使用不支持的旧版SQL Server客户端通信软件进行连接

    一般提示这种错误的是arcgis服务区和SQL server服务器不在同一台电脑上,但在同一个局域网. 遇到这种问题是arcgis 服务器客户端连接SQL server数据库有问题,要么是客户端没有安 ...