如何一秒钟从头构建一个 ASP.NET Core 中间件
前言
其实地上本没有路,走的人多了,也便成了路。 -- 鲁迅
就像上面鲁迅说的那样,其实在我们开发中间件的过程中,微软并没有制定一些策略或者文档来约束你如何编写一个中间件程序, 但是其中却存在者一些最佳实践的方法,大多数人来使用这种方法来使应用程序变得更加容易理解并且易于维护,这就叫“路”,在2017年,这叫套路。
在掌握了这些套路之后,能够帮助你迅速的搭建一个中间件的基本框架,并且易于扩展和维护,下面我们就来看看怎么样从头开始开发一个中间件吧。
如果你对 ASP.NET Core HTTP 管道还不太清楚的话,下面这篇文章将有助于你对其进行一个系统的了解:
http://www.cnblogs.com/savorboard/p/aspnetcore-http-pipeline.html
Getting Started
说明: 这只是通常情况下,具体的情况还请使用具体的套路。
Setup 1 创建扩展类
如果你的中间件需要一个向 ASP.NET Core 的 DI 容器中添加默认的一些服务的话,那么你就编写一个需要扩展类,用来在 Startup.cs 中的 ConfigureServices 中注册服务。
举例,Microsoft.AspNetCore.ResponseCompression 这是一个用来压缩请求内容的一个中间件,那么它就需要一个服务用来处理压缩相关的东西,所以它扩展了 IServiceCollection 并且添加了自己的 Services。
整个中间件的核心代码并非在这里,这里只是一个开始,那么有同学可能会问了,什么情况下我们需要提前向一个DI里面注入我们中间件需要的服务呢? 答案是,如果你不知道或者不确定你需要什么样的服务的时候,跳过此步骤,进入下一步,再等你需要的时候再回头来补上就是。
那么,我们先看一下编写一个扩展Service的静态类应该怎么做?
首先,新建一个以 xxxServicesExtensions
文件名结尾的静态类,用来编写注入DI的扩展方法。
类建立完成之后,需要向里面添加内容了。通常情况下,中间件中 Service 的扩展方法都是以 Addxxx(this IServiceCollection services)
开头来命名。在这里有一个需要注意的地方就是它的命名空间,通常情况下我们使用 using Microsoft.AspNetCore.Builder
这个命名空间。
然后,方法里面就是需要注册的服务了。假设我们需要向里面注册一个 IResponseCompressionProvider
和 它的实现类 ResponseCompressionProvider
,那么最终的扩展方法可能看起来是这样的。
using System;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.AspNetCore.Builder
{
public static IServiceCollection AddResponseCompression(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
services.TryAddSingleton<IResponseCompressionProvider, ResponseCompressionProvider>();
return services;
}
}
Setup 2 创建配置类
有的时候,用户在使用我们编写的中间件的时候,我们需要向提供者提供一些配置项,这些配置项在中间件执行之前用来传递一些必要参数信息或者是一些设置信息。举个我们熟悉例子,我们在使用 MVC 中间件的时候,可能会看到以下写法:
// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
var userDefinedFilter = new xxxFilter();
services.AddMvc(x => x.Filters.Add(userDefinedFilter));
}
可以看到,用户可将一些自定义的 Filter 传入到中间件的,然后中间件在运行的时候,我们传入的 Filter 就生效了。
注意,中间件使用的配置项有两种添加方法,一种是添加到
AddMiddleware(Action<xxxOptions> option)
另外一种是UseMiddleware<>(Action<xxxOptions> option)
,那么这两种有什么区别呢?
那么,前者Add中的配置项一般情况下是中间执行之前就需要的一些信息,也就是说中间件的启动就依赖于这些配置项,他放置于容器配置(Add DI Service)的时候添加进去更加方便或者合适的时候使用它,另外一种(后者)是容器已经构建完毕,不需要依赖于容器提供的配置项可以使用此种方式。
同样的道理,当你自己为你的用户编写一个中间件的时候,当你也需要用户可以自定义一些配置或者需要传入一些参数的时候,你也可以这么做。那到底怎么样做呢? 我们一起来看看。
首先,我们需要一个 xxxOptions
结尾的配置类,用来配置我们中间件需要的一些配置项。我们还是以上面的压缩中间件举例。
public class GzipCompressionProviderOptions : IOptions<GzipCompressionProviderOptions>
{
public CompressionLevel Level { get; set; } = CompressionLevel.Fastest;
GzipCompressionProviderOptions IOptions<GzipCompressionProviderOptions>.Value => this;
}
它其中配置了一个压缩的等级 CompressionLevel
,这是一个枚举字段。 然后我们可以看到,这个类它继承了 IOptions<out T>
接口,这是一个知识点,什么意思呢? IOptions<out TOptions>
是 ASP.NET Core 新的一个配置体系里面的一个接口,当你实现这个接口之后,ASP.NET Core DI 容器提供了了一个 services.Configure<xxxOptions>
这样的方法来让你把配置项注入到容器中,当然你也可以将配置项和 appsetting.json 中的配置关联起来,以便于配置一些在运行期可能需要变动信息。更多关于 IOptions<T>
的信息可以看 这里的翻译。
这个 xxxOptions
类通常情况下会提供一些默认值,也就是说当用户不提供这些参数的时候,你需要有一个合理的机制或者默认值来正常运行你的中间件。
假如你的配置项有很多,也就是说还有进一步比较细化的配置,那么你可以做一个封装,就像MVC的Options类一样,这样能够给你的中间件提供更加合理的维护和扩展。
Setup 3 核心中间件
接下来,就是我们的核心代码类了,通常情况下会有一个 xxxMiddleware
结尾的类用来处理 HTTP 管道请求中的一些业务,这个类的构造函数中已经可以使用在Setup1或者Setup2中向DI容器中注册的服务了。
按照约定,Middleware 类中需要有一个 Invoke 方法,用来处理中间件的核心业务,它的签名如下:
public Task Invoke(HttpContext httpContext);
注意,这是一个约定方法,并没有接口来约束它。在 Invoke
方法中,是中间件实现的核心代码。 示例如下:
public class xxxMiddleware
{
private readonly RequestDelegate _next;
public xxxMiddleware(RequestDelegate next)
{
if (next == null)
{
throw new ArgumentNullException(nameof(next));
}
_next = next;
}
public async Task Invoke(HttpContext context)
{
// ......
await _next(context);
return;
}
}
在 xxxMiddleware
这个里面有一个构造函数参数 RequestDelegate
,它是一个委托,代表的需要执行的下一个中间件,通常情况下我们会把它放到我们业务代码的末尾。
Setup 4 中间件扩展注册
中间件有三种注册方法(Run,Map,Use),我们暂不考虑Run和Map,因为他们只适用于很小和少的一些情况
完成了以上工作后,接下来,我们需要把中间件注册到我们的 ASP.NET Core 的执行,这个时候我们需要一个 xxxBuilderExtensions
类,它也是一个静态类,注意它的命名空间通常为
Microsoft.AspNetCore.Builder
,因为这个用户在使用我们的中间件的时候就不必再添加额外的命令空间,依靠 Visual Studio 的智能提示就可以很快速的搜索到。我们来看一下示例:
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.AspNetCore.Builder
{
public static class xxxBuilderExtensions
{
public static IApplicationBuilder UseResponseCompression(this IApplicationBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
return builder.UseMiddleware<xxxMiddleware>();
}
}
}
Yeoman 一秒钟
有同学可能会说了,这些套路既然是这样的,那么有没有什么代码生成工具来帮我做这些事情呢?答案是肯定的。
博主已经帮你们把工具做好了,它使用的是当今最流行的脚手架工具 npm 中的 Yeoman 。使用它可以帮助你迅速的搭建一个中间件解决方案代码模板,让你专注于业务开发。
我已经把这个模板上传于 Yeoman 的仓库中,你只需要按照如下命令就可以帮你自动生成一套 ASP.NET Core 中间件解决方案代码模板了,当然单元测试也包含其中。
npm 工具的安装相信你自己可以的。下面是安装 Yeoman 工具和博主的模板工具。
// 安装 Yeoman 脚手架工具 -g 命令为全局安装
npm install -g yo
// 安装博主的 Yeoman(ASP.NET Core Middleware)模板
npm install -g generator-aspnetcore-middleware
然后选择你需要生成解决方案的文件夹,使用如下命令生成。
yo aspnetcore-middleware
注意:生成的过程中需要输入你中间件的名称。按要求输入即可。
总结
本篇文章主要讲述了从头创建一个 ASP.NET Core 的流程,这适用于大多数场合,但是并不代表所有的场合,在实际开发的过程中还需要具体的考虑一下。接着博主提供了一个yo自动化脚手架模板用来快速创建一个中间件解决方案。
如果你觉得这篇文章对你有帮助的话,谢谢你的【推荐】。
如果你对 .NET Core 感兴趣可以关注我,我会定期在博客分享关于 .NET Core 的学习心得。
本文地址:http://www.cnblogs.com/savorboard/p/generator-aspnetcore-middleware.html
作者博客:Savorboard
欢迎转载,请在明显位置给出出处及链接
如何一秒钟从头构建一个 ASP.NET Core 中间件的更多相关文章
- 从实体框架核心开始:构建一个ASP。NET Core应用程序与Web API和代码优先开发
下载StudentApplication.Web.zip - 599.5 KB 下载StudentApplication.API.zip - 11.5 KB 介绍 在上一篇文章中,我们了解了实体框架的 ...
- NHibernate构建一个ASP.NET MVC应用程序
NHibernate构建一个ASP.NET MVC应用程序 什么是Nhibernate? NHibernate是一个面向.NET环境的对象/关系数据库映射工具.对象/关系数据库映射(object/re ...
- Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群
Kubernetes简介 Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的 ...
- 构建基于asp.net core 的docker应用并发布
发布Docker镜像的方法有很多种,asp.net core的发布需要在windows系统中 开门见山,首先保证已经在Centos上安装好了Docker.创建一个asp.net core的webapi ...
- 使用Visual Studio Code创建第一个ASP.NET Core应用程序
全文翻译自:Your First ASP.NET Core Application on a Mac Using Visual Studio Code 这篇文章将向你展示如何在Mac上写出你的第一个A ...
- 从零写一个Asp.net core手脚架(模型验证)
一个asp.net core项目,一定包含了各种的实体,在RESTful api里面,有很多的参数传递,不建立实体则大量的参数需要自定验证正确性,并且Action上面会写的密密麻麻的参数 在asp.n ...
- ASP.NET Core中间件实现分布式 Session
1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件的配置 1.2. 依赖注入中间件 1.3. Cookies ...
- ASP.NET Core 入门教程 9、ASP.NET Core 中间件(Middleware)入门
一.前言 1.本教程主要内容 ASP.NET Core 中间件介绍 通过自定义 ASP.NET Core 中间件实现请求验签 2.本教程环境信息 软件/环境 说明 操作系统 Windows 10 SD ...
- ASP.NETCore学习记录(二) —— ASP.NET Core 中间件
ASP.NET Core 中间件 目录: 什么是中间件 ? IApplicationBuilder 使用 IApplicationBuilder 创建中间件 Run.Map 与 Use 方法 实战中间 ...
随机推荐
- SD卡兼容性问题(转)
看到一篇关于硬件抗干扰的应用实例,很有参考值.所以,转过来方便查找. 源文:SD卡兼容性问题 最近碰到了一个SD卡兼容性的问题.主芯片SD卡组的信号,经过转接板,长排线,然后再到SD卡子板之后.对多种 ...
- leetcode--012 single number I
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA0MAAADGCAIAAACfN8xOAAAZ6UlEQVR4nO3dsZKcurbG8fNOnd1nIv
- 安卓 异步线程更新Ui
异步跟新UI: 1.handler+Thread(runnable):如果handler和Thread都写在了一个Java文件中,就不说了,如果runnable定义在了一个单独的类文件中,可以通过在构 ...
- C语言-指针、数组、结构体、分支、循环混合使用
1.写一个程序,输出如下内容: //############################################################# //### name number ma ...
- AtCoder Beginner Contest 052 ABCD题
A - Two Rectangles Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement The ...
- 【贪心】【堆】Gym -100956D - Greedy Game
题意:给定n个物品,每个物品对于A和B来说具有不同的价值,记为ai,bi,两人交替取,A先手,A总是贪心地取当前剩下的物品中,对于他价值最高的,如果有多个,则任取一个.问B在最坏情况下,能取到的物品的 ...
- object-c中的BOOL类型
object-c中的布尔类型比C语言中的bool类型早了10年,它具有YES和NO两种值.在object-c中的布尔类型BOOL实际上是一种带符号的字符类型(signed char),它使用的空间是1 ...
- 12.TCP的成块数据流
1.滑动窗口协议 TCP滑动窗口的可视化表示 我们将字节从1到11进行标号,接收方通告的窗口称为提供的窗口,它覆盖了第4字节到第9字节的数据,且通告窗口大小为6.发 ...
- 10.TCP连接的建立与终止
1.建立连接协议 (1)请求端发送一个SYN段指明客户打算连接的服务器的端口,移机初始序号ISN.这个SYN段为报文段1. (2)服务器发回包含服务器的初始序号的SYN报文段作为应答.同时,将确认 ...
- 直播流怎么存储在Ceph对象存储上? Linux内存文件系统tmpfs(/dev/shm) 的应用
一./dev/shm理论 默认的Linux发行版中的内核配置都会开启tmpfs,映射到了/dev/下的shm目录.可以通过df 命令查看结果./dev/shm/是linux下一个非常有用的目录,因为这 ...