前言

其实地上本没有路,走的人多了,也便成了路。 -- 鲁迅

就像上面鲁迅说的那样,其实在我们开发中间件的过程中,微软并没有制定一些策略或者文档来约束你如何编写一个中间件程序, 但是其中却存在者一些最佳实践的方法,大多数人来使用这种方法来使应用程序变得更加容易理解并且易于维护,这就叫“路”,在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 中间件的更多相关文章

  1. 从实体框架核心开始:构建一个ASP。NET Core应用程序与Web API和代码优先开发

    下载StudentApplication.Web.zip - 599.5 KB 下载StudentApplication.API.zip - 11.5 KB 介绍 在上一篇文章中,我们了解了实体框架的 ...

  2. NHibernate构建一个ASP.NET MVC应用程序

    NHibernate构建一个ASP.NET MVC应用程序 什么是Nhibernate? NHibernate是一个面向.NET环境的对象/关系数据库映射工具.对象/关系数据库映射(object/re ...

  3. Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群

    Kubernetes简介 Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的 ...

  4. 构建基于asp.net core 的docker应用并发布

    发布Docker镜像的方法有很多种,asp.net core的发布需要在windows系统中 开门见山,首先保证已经在Centos上安装好了Docker.创建一个asp.net core的webapi ...

  5. 使用Visual Studio Code创建第一个ASP.NET Core应用程序

    全文翻译自:Your First ASP.NET Core Application on a Mac Using Visual Studio Code 这篇文章将向你展示如何在Mac上写出你的第一个A ...

  6. 从零写一个Asp.net core手脚架(模型验证)

    一个asp.net core项目,一定包含了各种的实体,在RESTful api里面,有很多的参数传递,不建立实体则大量的参数需要自定验证正确性,并且Action上面会写的密密麻麻的参数 在asp.n ...

  7. ASP.NET Core中间件实现分布式 Session

    1. ASP.NET Core中间件详解 1.1. 中间件原理 1.1.1. 什么是中间件 1.1.2. 中间件执行过程 1.1.3. 中间件的配置 1.2. 依赖注入中间件 1.3. Cookies ...

  8. ASP.NET Core 入门教程 9、ASP.NET Core 中间件(Middleware)入门

    一.前言 1.本教程主要内容 ASP.NET Core 中间件介绍 通过自定义 ASP.NET Core 中间件实现请求验签 2.本教程环境信息 软件/环境 说明 操作系统 Windows 10 SD ...

  9. ASP.NETCore学习记录(二) —— ASP.NET Core 中间件

    ASP.NET Core 中间件 目录: 什么是中间件 ? IApplicationBuilder 使用 IApplicationBuilder 创建中间件 Run.Map 与 Use 方法 实战中间 ...

随机推荐

  1. 结合实际项目分析pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  2. 非root用户Memcached repcached安装

    安装memcached前先要确定系统是否安装了gcc: 1.解压安装包: tar -zxf memcached-1.2.8-repcached-2.2.tar.gz 2.编译: 系统应安装了libev ...

  3. 用编程的方式定义UI界面

    package com.example.administrator.test_hello_world; import android.app.Activity; import android.os.B ...

  4. iOS 之 关闭键盘

    //方法一:关闭整个系统的键盘 [[[UIApplication sharedApplication] keyWindow] endEditing:YES]; //方法二:关闭当前页的键盘 [[sel ...

  5. php防止重复提交表单

    解决方案一:引入cookie机制来解决 提交页面代码如下a.php代码如下: <form id="form1" name="form1" method=& ...

  6. 如何解决PHP+MySQL出现乱码的现象

    在使用PHP+MYSQL时,您是否遇到过字符乱码的问题呢?您是如何解决这个问题的呢?这里提供了一种解决之道. 在mysql_connect后面加一句SET NAMES UTF8,即可使得UTF8的数据 ...

  7. centos 单独安装nginx

    安装包下载网址: http://nginx.org/en/download.html 进入Linux文件夹执行 wget http://nginx.org/download/nginx-1.8.0.t ...

  8. spring异常处理

    http://cgs1999.iteye.com/blog/1547197 1 描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到 ...

  9. iOS 之 assign、retain、copy、nonatomic

    1. assign 1.1. 普通赋值 一般用于基本类型 1.2. 常见委托设计模式 防止循环引用 2. retain 保留计数,获取了对象的所有权.引用计数在原有基础上加1. 3. copy 同re ...

  10. 2.8. 创建 NSManagedObject 的子类 (Core Data 应用程序实践指南)

    现在根据模型来创建NSManagedObject的子类.如果模型改变了,那就就重新生成这些文件.所以,不要在生成的文件里自定义方法,因为重新生成之后,这些修改就丢失了.假如确实需要重新生成自定义的方法 ...