如何设计出和 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说明文档对于程序员来说想必 ...
随机推荐
- win32命令行小程序获取指定文件夹或者目录下面的所有文件大小,文件数量,目录数量
#include <Windows.h> #include <stdio.h> #include <tchar.h> LARGE_INTEGER lgA ...
- MySQL实现类似Oracle中的nextval和currval
CREATE TABLE `sequence` ( `seq_name` varchar(50) NOT NULL, `current_val` int(11) NOT NULL, `incremen ...
- python于lxml应用
首先下载lxml, http://www.lfd.uci.edu/~gohlke/pythonlibs/ ,然后加入引用 from lxml import _elementpath as DONTUS ...
- Parallel.For
Parallel.For 你可能忽视的一个非常实用的重载方法 说起Parallel.For大家都不会陌生,很简单,不就是一个提供并行功能的for循环吗? 或许大家平时使用到的差不多就是其中最简单 ...
- [福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus
Chrome Sniffer Plus: Chrome 探测器,可以探测正在使用的开源软件或者 js 类库,开发者必备. 通过本插件,您可以探测: javascript 库: jQuery.ExtJS ...
- .net命名空间和程序集详解
命名空间是一种用于将逻辑上相似的类按层次结构分组的机制.这种机制防止了命名冲突.在这种结构化采用被点号"."分隔的单词来实现.通常最顶层的命名空间是System,例如System; ...
- centos7 Intellij Idea 授权服务器搭建(Jetbrain 家族系列IDE)
centos7 Intellij Idea 授权服务器搭建 1.上传破解文件 我用的是Xshell客户端,有上传功能,但是linux必须先装lrzsz,也可以通过其他方式传到linux上 yum -y ...
- Spring RestTemplate 专题
相同的参数(接口的入参json打印在日志了)在PostMan中返回预期的数据,但使用RestTemplate时去提示信息错误(参数中汉字).这种情况,搞得怀疑对RestTemplate的理解了使用Re ...
- C# VS 2010创建、安装、调试 windows服务(windows service)
在一个应用程序中创建多个 windows 服务的方法和 1083 的解决办法 错误解决方案 ------------------------------------------------------ ...
- 在codefirst迁移的时候 为新增的属性添加一个默认值
在模型中新增一个属性之后 通过add-migration ConsulationMsg_add_IsDel命令之后 会生成一个 日期+ConsulationMsg_add_IsDel的类文件 打开类文 ...