使用ASP.NET Core 3.x 构建 RESTful API – 1.准备工作
以前写过ASP.NET Core 2.x的REST API文章,今年再更新一下到3.0版本。
先决条件
我在B站有一个非常入门的ASP.NET Core 3.0的视频教程,如果您对ASP.NET Core不了解,就可以先看一下里面的基础知识和API相关的内容,地址是: https://www.bilibili.com/video/av65313713/ 。
预备知识:ASP.NET Core 和 C#
工具:Visual Studio 2019最新版( VSCode 、 VS for Mac ,Rider等也凑合), POSTMAN
Web API
Web API 通常是指“使用 HTTP 协议并通过网络调用的API”,由于它使用了 HTTP 协议,所以需要通过URI信息来指定端点。
API是 Application Programming Interface 的缩写,是软件的外部接口。也就是说,针对某个软件,人们可以知道它的外部功能,但并不知道(也不需要知道)它的内部运作细节,为了从外部调用某些功能,需要指定软件的调用规范等信息,这样的规范就是API。
所以Web API 就是一个 Web 系统,通过访问URI可以与其进行信息交互。
大多数的 Web API 并不是 RESTful API
REST 一词是在 2000 年首次出现的,它是由Roy Fielding 博士在《架构风格以及基于网路的软件架构设计》这篇论文中提到的。他为REST风格的API制定了一套约束规范或者叫 架构风格 。
所以准确的说,只有符合了Roy Fielding 架构风格的Web API 才能称作是 RESTful API 。但是在实际开发中,有时候也有不完全符合Roy Fielding 架构风格的情形出现,针对这点我将会在稍后的文章中介绍。
MVC 模式与 RESTful API
本系列文章中我将使用ASP.NET Core 3.0 MVC 来构建 RESTful API。
MVC( Model-View-Controller )我认为是一种主要用来构建 UI 的架构模式。对于 MVC 模式其实有很多种解释存在,但是无论那种解释,它们都会强调松耦合和关注点分离( separation of concerns )。
也是由于这两点的存在,程序的可测试性会大大提高,程序各部分的可复用性也很高。
更多关于MVC的介绍,可以看一下微软的官方文档: https://docs.microsoft.com/zh-cn/aspnet/core/mvc/overview?view=aspnetcore-3.0
注意:MVC不是一个完整的应用程序架构,我认为它主要是用在展示层。所以实现 UI 就是 MVC 的一部分工作。
如何把 MVC 映射到 API
我认为 API 同样可以看作是UI,它就是为 API 消费者所提供的UI。
让我们把MVC的三部分分别对应到API:
-
Model,它负责处理程序数据的逻辑。这里的 Model 可以包含在当前级别获取从存储获取数据的逻辑。但是有一些 Model 不包含任何逻辑,例如 API 所使用的 DTO ( Data transfer objects ),这类的 Model 会被串行化到响应的body里面。
-
View,它是程序里负责展示数据的那部分。在构建API的时候, View 就是数据或资源的展示。现在通常使用JSON格式。
-
Controller,它负责 View 和 Model 之间的交互。包括处理用户输入,用API的术语来讲,和API交互的“用户”就是指API的消费者,这类用户通常是另一个程序,例如 Angular 的SPA程序。
下面看看MVC这三部分的依赖关系:
Controller和 View 依赖于 Model , Controller 依赖于 View ,这也是分离的一个好处。
换句话说, Controller 会选取适当的View来展现给用户,并一同把用户请求的 Model 数据带回去。
当API消费者发出请求的时候,在 Controller 上面的 Action 将会被触发, Controller 会把接收到的输入数据发送给负责业务处理逻辑或数据访问逻辑的那部分程序。然后 Controller 会把Model返回给 View ,这里的 View 就是资源的展示(通常是 JSON 格式)。
接下来我们就是用这套概念和ASP . NET Core 3.0 来创建 RESTful API 。
但是请注意,通过ASP . NET Core MVC 或API模板建立出来的新项目,我们并不会直接得到 RESTful (REST架构风格)的 API 。我们必须在这个基础上,自己构建 RESTful 的API,因为之前已经提到了,标准的 RESTful API 有很多约束和规范。
创建 ASP . NET Core 3.0 Web API 项目
打开 VS2019 ,选择项目模板 ASP . NET Core Web Application :
然后为项目和解决方案起名字,并选择所在目录:
然后选择 ASP . NET Core 的项目模板:
首先要选择 ASP . NET Core 3.0 。
这里我选择了 API 这个模板。在以前,我通常会选择 Empty 模板,因为其它模板通常包含很多我不需要的东西,但是 ASP . NET Core 3.0 的API模板还是比较干净的,可以接受。
最后,由于本课程中不需要使用 HTTPS 和 Docker ,所以把这两个东西都勾掉。
解剖 ASP . NET Core 3.0 API 模板项目
点击 Create ,项目就建立好了:
先看看 appsettings.json :
里面只有默认的 Log 配置以及允许的 Hosts 。
而 appsettings.Development.json 里面:
也只有关于 Log 的默认配置。
注意:您需要知道 appsettings.json 和 appsettings.Development.json 之间的关系,关于这点可以看我 ASP.NET Core 3.0的入门视频教程 ,但是更简单的办法是看一下官方文档: 在ASP.NET Core中使用多个环境 。
项目模板里还有两个类我们不需要,所以把它删掉,分别是 WeatherForecastController 和 WeatherForecast :
Program . cs :
这里其实就是整个程序的入口,Main方法负责配置和运行整个 Web 程序。
由于这是一个 Web 项目,所以我们还需要一个宿主( Host ),这个宿主就是由下面的Create HostBuilder 方法来负责创建的。该方法首先会创建出一个实现了 IHostBuilder 接口的类( HostBuilder )的实例,然后调用它的Build方法来创建宿主(类型为 Host ,实现了IHost接口),最后调用宿主上面的Run方法来运行程序。
我们暂时不修改这里面的代码,所以一切都会按照项目模板默认的配置进行,注意到下面的方法里我们使用到了 Startup 这个类:
所以我们来看看 Startup 类。
Startup .cs
在这个类的构造函数里:
我们看到 IConfiguration 被注入了,这样就允许我们使用配置信息了,例如 appsettings . json里面的配置信息。
下面有一个 ConfigureServices 方法:
这个方法负责向服务容器里面注册服务,已注册的服务可以通过依赖注入的方式在整个应用程序的其它地方进行使用。这里的服务是一个比较广义的概念,它就是一个在整个程序中做一些通用性操作的组件。
这里面只有一句话:
在 3.0 之前的版本里,这里面应该写的是services .AddMvc(); ,实际上在ASP . NET Core 3.0 里面这样写也是可以的。但是AddMvc () 里面不仅仅包含用于构建API的服务,还包含很多其它服务,例如构建View视图和TagHelper相关的服务等。而Add Controller s () 方法只包含用于构建API的那些服务,例如 Controller 的支持、Model绑定、Data Annotation 和格式化器等等。
最下面还有一个 Configure 方法:
这个方法使用到了在 ConfigureServices 方法里面注册和配置的服务,所以这个方法是在 ConfigureServices 方法之后被调用的。
Configure 方法是用来指定ASP . NET Core Web 程序是 如何响应每一个 HTTP 请求的 。换句话说,也就是我们在这里配置请求的管道,配置的方法就是在这里添加很多中间件( Configure 方法里面每一个 app . UseXxx 就是添加一个中间件,可以查看 中间件的官方文档 来了解更多)。
在开发环境的时候,如果有异常发生,那么会展示出一个异常页面:
app . UseAuthorization () ,它会为整个Web程序添加授权的能力。当你需要考虑API安全性的时候,这点就很重要了。通常授权配置是在 ConfigureServices 方法里完成的,而我现在没有对授权进行配置,但是 app . UseAuthorization () 仍然会允许 API 可以被匿名的访问。
其它这几句话:
这几句话都是用来指定如何把HTTP请求分配到特定的Controller Action 上面的。也就是说这是关于 路由 的。
很重要的一点就是:每一个请求会按照代码的顺序穿越所有在这里添加的中间件。但是每一个中间件都有可能将请求短路,这样的话请求就不会进入下一个中间件了,而会按照原路返回。
所以,添加中间件的顺序非常重要。如果你把授权中间件放在了 Controller 的后边,那么即使需要授权,那么请求也会先到达 Controller 并执行里面的代码,这样的话授权就没有意义了。
修改项目启动配置
我喜欢使用控制台启动Web程序,这样可以很直观的看到Log信息。为达到这个目的,可以修改launchSettings . json 文件:
修改后,在项目的Debug属性里也有体现:
由于我主要是使用POSTMAN来调用API,所以我不需要Launch Browser (启动浏览器)。
运行程序
可以看到程序可以正常运行,并且在控制台上有日志的输出。
添加数据存储功能
想要做 RESTful API 的话,我们还需要数据,这里我准备采用 SQLite 来作为数据存储,使用 Entity Framework Core 作为 ORM 来与数据库进行交互。针对 Entity Framework Core 3.0 如何在 ASP . NET Core 里面使用,官方有个很不错的 教程 。
下面开始在项目里添加 SQLite 和 EFCore 3.0 (这部分官方文档可以 点击这里 )的支持:
-
首先,需要在我们的项目里通过 Nuget 添加 Microsoft.EntityFrameworkCore.Sqlite 这个包。
-
然后,还需要安装 Microsoft.EntityFrameworkCore.Tools 这个包,它是用来做迁移的,关于这个包的更多功能解释,可以查看 官方文档 。
建立 Entities
我们先把项目的需求想的简单一点,暂时我们就做一个公司和公司员工的维护,两个 Entity ,两个表。
公司( Company )的Entity:
为什么使用Guid作为主键的类型?
员工( Employee )的 Entity :
还涉及到一个性别的枚举:
建立 DbContext
建立一个文件夹 DbContexts ,在里面建立一个类名叫 RoutineDbContext :
关于这个类的理解并不是本文的重点,想知道详细的解释可以查看这部分的 官方文档 。
-
这个类需要继承于 DbContext ,而 DbContext 需要 DbContextOptions 才能工作,所以我采用了构造函数接收参数的形式来接收 DbContextOptions 。
-
中间的两个 DbSet 属性就可以简单的理解为把 Entity 映射到了数据库中的一个表。
-
最下面我重写了 OnModelCreating 这个方法。在里面,我对两个 Entity 的某些属性做了一些限制。关于这部分的详细内容,也可以查看 官方文档 。在方法的最后,我显式的指明了两个 Entity 之间的关系为一对多关系,并指明了外键。其实按照约定,它们两个之间的一对多关系是默认已经成立的,无需我来指明。
添加种子数据
还是在 RoutineDbContext 这个类里的 OnModelCreating 方法里,我添加如下代码来为数据库添加种子数据:
这里只添加了 Company 数据。
建立 Repository
如果只是用来讲解 RESTful API 的话,不使用 Repository 等 Service 也行,就是直接在 Controller 里面使用 DbContext 也可以接受。但是我还是简单的写一个 Repository 吧(这个Repository并不是很规范),否则重复代码可能比较多。
首先看一下ICompanyRepository,也就是 Repository 的接口合约:
里面的功能我相信大家应该能看明白吧。
然后看一下实现, CompanyRepository :
比较长。。。
注册服务
在Startup的 ConfigureServices 方法里把 DbContext 和 Repository 注册到容器里:
关于这部分的知识,可以看官方文档: 服务生命周期 和 配置DbContext 。
修改 Program
为了演示方便,我让数据库在每次程序启动的时候都会被删掉并重新进行迁移,同时设置好种子数据。这部分内容可查看 迁移的官方文档 和 创建删除 API 的官方文档 。
这里只修改了Main方法:
添加迁移
打开VS 2019 的Package Manager Console ,并输入类似以下的命令来添加迁移:
命令执行成功后,会生成一个 Migrations 文件夹:
里面包含着这个这次的迁移类和 当前模型的快照 。
运行程序
可以看到执行了一些SQL语句,并且出现的Log都是绿色的Info,这说明数据库已经建立成功了。
看一下项目文件:
可以看到数据库已经成功的被建立了。
打开数据库:
可以看到种子数据已经成功写入。