让 .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. Vue2.0 【第一季】第7节 v-bind指令

    目录 Vue2.0 [第一季] 第7节 v-bind指令 第7节 v-bind指令 v-bind缩写 绑定CSS样式 Vue2.0 [第一季] 第7节 v-bind指令 第7节 v-bind指令 v- ...

  2. js 面向对象 模拟日历

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 把读取sql的结果写入到excel文件

    1.利用pandas模块 # encoding: utf-8 import time import pandas as pd import pymysql def getrel(sql): ''' 连 ...

  4. react 新创建项目

    1,先创建一个文件夹用于存放项目 2,运行cmd,路径选择到你创建的文件夹内 3,  npm install -g create-react-app         create-react-app ...

  5. 当AI遇上K8S:使用Rancher安装机器学习必备工具JupyterHub

    Jupyter Notebook是用于科学数据分析的利器,JupyterHub可以在服务器环境下为多个用户托管Jupyter运行环境.本文将详细介绍如何使用Rancher安装JupyterHub来为数 ...

  6. 035.集群安全-Pod安全

    一 Pod安全 1.1 PodSecurityPolicy启用 为了更精细地控制Pod对资源的使用方式,Kubernetes从1.4版本开始引入了PodSecurityPolicy资源对象对Pod的安 ...

  7. Swift 4.0 字符串(String)学习

    定义字符串常量(常量只有读操作) let lString = "constant" let lString1: String = "constant" 定义字符 ...

  8. Spring Boot + LayUI 批量修改数据 数据包含着对象

    页面展示 HTML 代码 <blockquote class="layui-elem-quote demoTable"> <div class="lay ...

  9. F版本SpringCloud 2—什么是SpringCloud?SpringCloud版本选择

    引言:搭建微服务架构就像是买电脑,使用SpringCloud就是在买品牌机. 前言 昂,美好的天气里,不想直接说技术,给小伙伴萌看看傍晚的天空吧. -- 能找到天上的北极星吗? 上一篇文章中,通过一个 ...

  10. c++动态内存知识总结与疑问

    书名  BOOK TITLE <Primer c++  第5版> 基本信息 BASICS 阅读进度:第12章动态内存 阅读心得 LEARNINGS 在c++中,我知道的有静态内存.栈内存. ...