如何设计出和 ASP.NET Core 中 Middleware 一样的 API 方法?
由于笔者时间有限,无法写更多的说明文本,且主要是自己用来记录学习点滴,请谅解,下面直接贴代码了(代码中有一些说明):
01-不好的设计
代码:
using System; namespace DesignSample
{
public class TrTemplateContext { public string TrAttrPrefix { get; set; } } class Program
{
public static void Main(string[] args)
{
AppendTimeForTrTag(c => string.Format("{0}-id=\"{1}\"", c.TrAttrPrefix, "tr1"));
//很显然,这是一个糟糕的设计,意味着每增加一个类似 AppendTimeForTrTag 的封装就
//要增加很多类似于 AppendTimeForTrTag 的代码。参考 ASP.NET Core 中的 middleware
} static void AppendTimeForTrTag(Func<TrTemplateContext, string> trTemplate)
{/* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */
Func<TrTemplateContext, string> trTimeTemplate =
c => string.Format("{0}-time=\"{1}\"",
c.TrAttrPrefix,
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
Func<TrTemplateContext, string> trAllTemplate = trTimeTemplate;
if(trTemplate != null)
{
trAllTemplate = c => trTimeTemplate(c) + " " + trTemplate(c);
}
PrintTrTag(trAllTemplate);
} static void PrintTrTag(Func<TrTemplateContext, string> trTemplate)
{/* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */
string htmlTempl = "<tr {0}></tr>";
string trInner = null;
TrTemplateContext templContext = new TrTemplateContext { TrAttrPrefix = "ng" };
if (trTemplate != null)
{
trInner = trTemplate(templContext);
}
string fullHtml = string.Format(htmlTempl, trInner);
Console.WriteLine(fullHtml);
}
}
}
运行结果:

02-中间件设计(未提取公共代码)
代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignSample
{
public class TrAttrTemplateContext
{
public string TrAttrPrefix { get; set; } private StringBuilder trAttrBuilder = new StringBuilder(); public void Add(string str)
{
if(trAttrBuilder.Length > )
{
trAttrBuilder.Append(" ");
}
trAttrBuilder.Append(str);
} public string GetAllString()
{
return trAttrBuilder.ToString();
}
}
public delegate void RequestDelegate(TrAttrTemplateContext builder);
public class TrAttrTemplateBuilder
{
private readonly List<Func<RequestDelegate, RequestDelegate>> _middlewares
= new List<Func<RequestDelegate, RequestDelegate>>(); public TrAttrTemplateBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
{
_middlewares.Add(middleware);
return this;
} public RequestDelegate Build()
{
_middlewares.Reverse();
RequestDelegate next = c => { };
foreach (var middleware in _middlewares)
{
next = middleware(next);
}
return next;
}
} class Program
{
public static void Main(string[] args)
{
PrintTrTag(app =>
app.Use(AppendIdForTrTag) //给 tr 标签增加 ng-id 属性
.Use(AppendTimeForTrTag) //给 tr 标签增加 ng-time 属性
);
} /* 假设本方法来自于你们公司的B部门,通过封装,用于给<tr>标签固定附加 ng-id 属性 */
static RequestDelegate AppendIdForTrTag(RequestDelegate next) => context =>
{
context.Add($"{ context.TrAttrPrefix }-id=\"tr1\"");
next(context);
}; /* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */
static RequestDelegate AppendTimeForTrTag(RequestDelegate next) => context =>
{
context.Add($"{ context.TrAttrPrefix }-time=\"{ DateTime.Now.ToString() }\"");
next(context);
}; /* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */
static void PrintTrTag(Func<TrAttrTemplateBuilder, TrAttrTemplateBuilder> trBuilderAction)
{
string htmlTempl = "<tr {0}></tr>";
string trAttrInner = null;
if (trBuilderAction != null)
{
TrAttrTemplateBuilder builder = new TrAttrTemplateBuilder();
builder = trBuilderAction(builder);
if(builder != null)
{
TrAttrTemplateContext templContext = new TrAttrTemplateContext { TrAttrPrefix = "ng" };
builder.Build()(templContext);
trAttrInner = templContext.GetAllString();
}
}
string fullHtml = string.Format(htmlTempl, trAttrInner);
Console.WriteLine(fullHtml);
}
}
}
运行截图:和 上图一样。
03-中间件设计(已提取公共代码)
代码:
SpaceMiddlewareBuilder.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DesignSample
{
/// <summary>
/// 空格中间件生成器
/// </summary>
/// <typeparam name="TDelegate">委托的类型</typeparam>
public class SpaceMiddlewareBuilder<TDelegate, TDelegateParam, TChild>
where TDelegate: Delegate
where TDelegateParam: SpaceMiddlewareContext
where TChild : SpaceMiddlewareBuilder<TDelegate, TDelegateParam, TChild>,new()
{
private readonly List<Func<TDelegate, TDelegate>> _middlewares
= new List<Func<TDelegate, TDelegate>>(); private TDelegate _defaultAction; /// <summary>
/// 构造一个空格中间件生成器
/// </summary>
/// <param name="defaultAction">默认执行的动作。无论是否有注册中间件,都会默认执行,除非在某一个中间件中拒绝调用 next(context)。不能为 NULL</param>
public SpaceMiddlewareBuilder(TDelegate defaultAction)
{
this._defaultAction = defaultAction ?? throw new ArgumentNullException(nameof(defaultAction));
} /// <summary>
/// 使用中间件
/// </summary>
/// <param name="middleware"></param>
/// <returns></returns>
public TChild Use(Func<TDelegate, TDelegate> middleware)
{
_middlewares.Add(middleware);
return (TChild)this;
} /// <summary>
/// 生成
/// </summary>
/// <returns></returns>
public TDelegate Build()
{
_middlewares.Reverse();
TDelegate next = this._defaultAction;
foreach (var middleware in _middlewares)
{
next = middleware(next);
}
return next;
} /// <summary>
/// 执行委托,返回附加的所有文本
/// </summary>
/// <param name="builderAction"></param>
/// <param name="delegateParam"></param>
/// <returns></returns>
public string Execute(Func<TChild, TChild> builderAction, TDelegateParam delegateParam)
{
if(builderAction == null)
{
return string.Empty;
}
TChild builder = new TChild();
builder = builderAction(builder);
if (builder == null)
{
return string.Empty;
}
TDelegate tDelegate = builder.Build();
if(tDelegate == null)
{
return string.Empty;
}
tDelegate.DynamicInvoke(delegateParam);
return delegateParam.GetAllText();
}
}
}
SpaceMiddlewareContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace DesignSample
{
/// <summary>
/// 空格中间件上下文
/// </summary>
public class SpaceMiddlewareContext
{
private readonly StringBuilder _textBuilder; /// <summary>
/// 构造函数
/// </summary>
public SpaceMiddlewareContext()
{
_textBuilder = new StringBuilder();
} /// <summary>
/// 增加一些文本字符串
/// </summary>
/// <param name="text"></param>
public void Add(string text)
{
if (_textBuilder.Length > )
{
_textBuilder.Append(" ");
}
_textBuilder.Append(text);
} /// <summary>
/// 获取到目前为止所有增加的文本字符串集合
/// </summary>
/// <returns></returns>
public string GetAllText()
{
return _textBuilder.ToString();
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignSample
{
public class TrAttrTemplateContext : SpaceMiddlewareContext
{
public string TrAttrPrefix { get; set; }
} public delegate void RequestDelegate(TrAttrTemplateContext arg); public class TrAttrTemplateBuilder : SpaceMiddlewareBuilder<RequestDelegate, TrAttrTemplateContext, TrAttrTemplateBuilder>
{
public TrAttrTemplateBuilder()
: base(c => { c.Add($"{ c.TrAttrPrefix }-ending=\"true\""); })
{ }
} class Program
{
public static void Main(string[] args)
{
//PrintTrTag(null); //Test 1
//PrintTrTag(app => app); //Test 2
PrintTrTag(app =>
app.Use(AppendIdForTrTag) //给 tr 标签增加 ng-id 属性
.Use(AppendTimeForTrTag) //给 tr 标签增加 ng-time 属性
);//Test 3
} /* 假设本方法来自于你们公司的B部门,通过封装,用于给<tr>标签固定附加 ng-id 属性 */
static RequestDelegate AppendIdForTrTag(RequestDelegate next) => context =>
{
context.Add($"{ context.TrAttrPrefix }-id=\"tr1\"");
next(context);
}; /* 假设本方法来自于你们公司的A部门,通过封装,用于给<tr>标签固定附加 ng-time 属性 */
static RequestDelegate AppendTimeForTrTag(RequestDelegate next) => context =>
{
context.Add($"{ context.TrAttrPrefix }-time=\"{ DateTime.Now.ToString() }\"");
next(context);
}; /* 假设本方法来自于ASP.NET Core内部。用于给<tr>标签附加一系列以 ng- 开头的属性 */
static void PrintTrTag(Func<TrAttrTemplateBuilder, TrAttrTemplateBuilder> trBuilderAction)
{
string htmlTempl = "<tr {0}></tr>";
string trAttrInner = new TrAttrTemplateBuilder().Execute(trBuilderAction, new TrAttrTemplateContext
{
TrAttrPrefix = "ng"
});
string fullHtml = string.Format(htmlTempl, trAttrInner);
Console.WriteLine(fullHtml);
}
}
}
谢谢浏览!
如何设计出和 ASP.NET Core 中 Middleware 一样的 API 方法?的更多相关文章
- ASP.NET Core中Middleware的使用
https://www.cnblogs.com/shenba/p/6361311.html ASP.NET 5中Middleware的基本用法 在ASP.NET 5里面引入了OWIN的概念,大致意 ...
- ASP.NET Core中,UseDeveloperExceptionPage扩展方法会吃掉异常
在ASP.NET Core中Startup类的Configure方法中,有一个扩展方法叫UseDeveloperExceptionPage,如下所示: // This method gets call ...
- ASP.NET Core中使用自定义路由
上一篇文章<ASP.NET Core中使用默认MVC路由>提到了如何使用默认的MVC路由配置,通过这个配置,我们就可以把请求路由到Controller和Action,通常情况下我们使用默认 ...
- 在 ASP.NET CORE 中使用 SESSION
Session 是保存用户和 Web 应用的会话状态的一种方法,ASP.NET Core 提供了一个用于管理会话状态的中间件.在本文中我将会简单介绍一下 ASP.NET Core 中的 Session ...
- 在 ASP.NET CORE 中使用 SESSION (转载)
Session 是保存用户和 Web 应用的会话状态的一种方法,ASP.NET Core 提供了一个用于管理会话状态的中间件.在本文中我将会简单介绍一下 ASP.NET Core 中的 Session ...
- ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- ASP.NET Core WebApi使用Swagger生成api
引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必是件很痛苦的事情吧,但文档又必须写,而且文档的格式如果没有具体要求的话,最终完成的文档则完全取决于开发者 ...
- ASP.NET Core WebApi使用Swagger生成api说明文档
1. Swagger是什么? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件 ...
- 【转】ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了
原文链接:https://www.cnblogs.com/yilezhu/p/9241261.html 引言 在使用asp.net core 进行api开发完成后,书写api说明文档对于程序员来说想必 ...
随机推荐
- [搜索]Trie树的实现
trie这种树也被称为线索,搜索树. 正如图 以下是用stl 的map来实现 class trie_item_c { public: trie_item_c(){} trie_item_c(const ...
- hadoop 3.x 启动过程中 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
出现这种状况是因为当前账号没有配置ssh免密登录 进入到以下目录,查看是否生成过秘钥对,如果有的话直接ssh-copy-id 主机名 没有的话执行ssh-keygen -t rsa后再重新执行ssh- ...
- 192M内存的VPS,安装Centos 6 minimal x86,无法安装node.js
尝试了各种方法,始终安装不了node.偶然一次,安装了64位的Centos 6 minimal,竟然可以安装Node官网给出的命令安装node了,一切顺利.
- ubuntu 16.0.4 中docker 部署 sqlserver 2017(四)
1. 从 Docker Hub 中拉出 SQL Server 2017 Linux 容器映像 sudo docker pull mcr.microsoft.com/mssql/server:2017- ...
- WCF客户端C#代码 配置config文件
不多说了,直接上代码吧.... 服务端Web.config文件中bindings配置 <bindings> <wsHttpBinding> <binding name=& ...
- Android Studio 报错Guest isn't online after 7 seconds 解决方案
最近使用真机模拟之后,再使用虚拟机就频繁出现这个问题; 解决步骤如下: 1.打开Android虚拟设备管理器, 2.查看Actoins栏下拉图标, 3.选择冷启动模式即可, 4.重启AVD正常;
- jQuery迭代器
http://www.imooc.com/code/3417 迭代器 迭代器是一个框架的重要设计.我们经常需要提供一种方法顺序用来处理聚合对象中各个元素,而又不暴露该对象的内部,这也是设计模式中的迭代 ...
- Android--在Android应用中愉快地写C/C++代码(转)
1 前言 一直想在android层面写c进程,然后java可以与c进程交互,以前在android源码中想玩就可以直接在init.rc中加上交叉编译好的c进程就可以了,而在ide中,也就是ndk编译后各 ...
- js 将json字符串转换为json对象
要引入:jquery-json-2.4.js 在数据传输过程中,json是以文本,即字符串的形式传递的,而JS操作的是JSON对象,所以,JSON对象和JSON字符串之间的相互转换是关键.例如: JS ...
- java项目采用exe4j打包成exe档
java项目采用exe4j打包成exe档 前言:我们都知道java是平台无关性.能够打包成jar文件,到不论什么操作系统有jre环境的电脑都能够同意!可是我们打包成exe文件就相当于舍弃了这一大优势, ...