如何设计出和 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说明文档对于程序员来说想必 ...
随机推荐
- 前端css实现最基本的时间轴
原型: 图片.png 代码: <!DOCTYPE html > <html> <head> <link rel="stylesheet" ...
- 【前端统计图】echarts改变颜色属性的demo
一:柱状图改变颜色 图片.png 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8&qu ...
- 一起学Python:协程
一:协程-yield 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一 ...
- ES6与React中this完全解惑
计划写很长的篇幅,预计12月初完成. 这篇文章涉及的知识较多,可能一次消化不了,可以渐渐来. 先说结论: 无论是ES6还是React的this,相对于ES5,只是增加了箭头函数this绑定了其封闭上下 ...
- 从华为产品学到什么是devops
根据Gartner 2015 I&O Automation 报告,DevOps处于技术发展的最高点,实践受到高度关注,到底devops魔力在哪里? 从devops实践看主要是打破开发人员和运营 ...
- vs中添加MySql实体集流程
默认情况下只有下图: 首先需要下载mysql为vs和ef提供的驱动(可以去官网下载对应的版本) 然后打开vs开始添加实体类 首先在NuGet中安装MySql.Data和MySql.Data.Entit ...
- jQuery分离构造器
http://www.imooc.com/code/3401 通过new操作符构建一个对象,一般经过四步: A.创建一个新对象 B.将构造函数的作用域赋给新对象(所以this就指向了这个新对象) ...
- Java--Vector类
Java Vector 类 Vector类实现了一个动态数组.和ArrayList和相似,但是两者是不同的: Vector是同步访问的. Vector包含了许多传统的方法,这些方法不属于集合框架. V ...
- Android--常用框架大全
1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图 ...
- Java设计模式透析之 —— 单例(Singleton)
写软件的时候经常需要用到打印日志功能,可以帮助你调试和定位问题,项目上线后还可以帮助你分析数据.但是Java原生带有的System.out.println()方法却很少在真正的项目开发中使用,甚至像f ...