如何设计出和 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说明文档对于程序员来说想必 ...
随机推荐
- Android网络应用之Socket(一)
socket编程是网络通信的一个基础应用.不管是手机端还是PC端都须要socket技术来建立网络通信. 在本章小编主要从下面几个方面来介绍socket的相关知识: 各自是"什么是socket ...
- 安装CentOS6.2操作系统
原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...
- 【a603】加工生产调度
Time Limit: 1 second Memory Limit: 32 MB [问题描述] 某工厂收到了n个产品的订单,这n个产品分别在A.B两个车间加工,并且必须先在A车间加工后才可以到B车间加 ...
- 【23.24%】【codeforces 629C】Famil Door and Brackets
time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...
- git如何更新fork的repository(Fork一个别人的repository,做了一些改动,再合并别人的更新)
Fork一个别人的repository,做了一些改动,想提交pull request的时候,发现原先别人的repository已经又有了一些更新了,这个时候想使得自己fork出的repository也 ...
- js限制文本框input只能输入数字
JS判断只能是数字和小数点. ,文本框只能输入数字代码(小数点也不能输入) 复制代码 代码示例:<input onkeyup="this.value=this.value.replac ...
- Android之消息推送实现
在开发Android和iPhone应用程序时,我们往往需要从服务器不定的向手机客户端即时推送各种通知消息,iPhone上已经有了比较简单的和完美的推送通知解决方案,可是Android平台上实现起来却相 ...
- python去噪算法
<programming computer vision with python >中denoise 算法有误,从网上好了可用的代码贴上,以便以后使用. 书中错误的代码: def deno ...
- 使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等
原文:使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等 WPF预设有Aero, Classic, Luna, Royale主题, WPF程序会根据 ...
- WPF“天狗食月”效果
原文:WPF"天狗食月"效果 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/deta ...