NET Core 并不只是一个新版本的.NET,它将我们.NET 开发人员从前学过的所有内容都
完整地翻新了一遍。.NET Core 是一个从零开始的全新产品,将.NET 开发以一种完全跨
平台的开发技术栈的面貌融入开源社区。
本章将逐个介绍 ASP.NET Core 和 .NET Core 的基础组件。按照微软的一贯风格,我们又
会有一系列新术语和名词需要了解。这些概念在测试版本和预发布版本期间,曾几经改
变,所以网上到处充斥着含糊不清甚至完全错误的信息。
读完本章,你将对 ASP.NET Core 本身,以及它如何适应跨平台框架的全新架构有更好的
了解。同时能在练习环境中完成所有依赖的配置工作,从而为本书后续章节做好准备。
1.1 核心概念
我非常希望直接开始基于 .NET Core 编写经典而必备的 Hello World 应用。不过 .NET
Core 在架构、设计和工具链上的改变十分彻底,我们最好花点时间了解几个与此前版本
的 .NET 不同的术语。
即使你之前从未用过 .NET,而直接使用 .NET Core,到网络上随便搜索也能到处见到这
些术语,所以非常有必要了解它们的含义。
1.1.1 CoreCLR
CoreCLR 是一个轻量级、跨平台的运行时,它提供了很多与 Windows 桌面或服务器版通
用语言运行时(Common Language Runtime, CLR) 相同的功能。
1. 垃圾回收
垃圾回收器负责清理托管应用中闲置的对象引用。如果用过 .NET( 或 Java) 此前的版本,
就一定对这一概念感到熟悉。尽管 CLR 和 CoreCLR 之间略有差异,但它们的垃圾回收
内部原理是一致的。
2. JIT 编译
与此前版本的 .NET 一样,JIT(Just-in-time,即时) 编译器负责将.NET 程序集中的中间语
言(Intermediate Language,IL) 代码按需编译为原生代码。这种机制仍被保留并扩展到
Windows、Linux 和 macOS 等平台。
3. 异常处理
异常处理( 例如try/catch 语句) 在运行时( 而不在基础类库) 使用。由于各种原因,这已超
出本书的讨论范围。
在 .NET 的第一个版本中,CLR 是一个大的单体程序,它提供 .NET 应用所需的基础服务。
随着时间的推移,它变得越来越大,与 Windows 的耦合也越来越紧密。它最终变得异常
庞大,完整的 CLR 对于大多数普通用户来说通常过于臃肿,微软不得不把它分成两个版
本,让开发人员选用完整版或轻量版。当时,开发人员一般根据他们开发的是服务器端还
是客户端应用来做出选择。
在 .NET Core 中,CoreCLR 现在只保留支持 .NET Core 应用运行所需各类基础服务的最
小集合。实际上,它只是一个启动器。任何不属于跨平台运行时最基础的部分,都放到
CoreFX 中,或以完全独立的扩展类库的方式提供。
1.1.2 CoreFX
从事过 .NET 应用开发的人应该比较熟悉基础类库(Base Class Library,BCL) 的概念,也
就是构成框架的所有类库的总称。只要在服务器上安装 .NET Framework 3.5 之类的软件,
就能获得框架提供的所有类型。这就使开发人员以为服务器上什么都是现成的,遗憾的
是,他们将服务器当作宠物( 后面会讨论为什么这种做法很糟糕)。
旧的 .NET Framework 犹如庞大的怪物,它有成千上万个类。往服务器上部署应用时,需
要安装整个框架,而不管应用实际用到其中多少。
CoreFX 是一系列模块化的程序集( 以NuGet 包的方式提供,并且完全开源,可通过 GitHub
获取),开发人员可从中挑选并使用。应用现在不再要求目标服务器上安装类库的所有程
序集。基于CoreFX,可以只关注真正用到的部分,按照真正的云原生风格,应用与其依赖
项应该打包到一起,对目标环境没有特殊要求。依赖管理的负担回到应用一侧后,服务器
也就不再需要提前配置。
这将极大地改变人们对 .NET 开发的印象。.NET 应用开发不再是一种基于 Windows 的
闭源和厂商锁定的技术。现在,它是一种轻盈、按需取用的模式,与现代化微服务开发的
模式与实践,以及广大开源社区所理解的软件开发哲学完全看齐。
1.1.3 .NET Platform Standard
在 .NET Core 之前,.NET 开发人员曾熟悉可移植类库(Portable Class Libraries,PCL) 的
概念。它们支持让开发人员面向不同的CPU架构和平台编译程序集( 例如,给 Windows
Phone 8 提供一个DLL,给在服务器上运行的 ASP.NET 应用再提供一个DLL)。这一过程
将生成多个不同的DLL文件,分别关联不同的目标部署平台。
.NET Platform Standard( 通常简称为.NET Standard) 旨在简化这一过程,以一种更可控的
架构支持 .NET Core 二进制可移植性的跨平台目标。关于.NET Standard 的更多信息,请
阅读位于GitHub 的文档。
也可将 .NET Standard 理解为一种接口。我们可将每个 .NET Standard 版本都理解成一系
列接口,并以传统的.NET Framework( 在v4.x 及以上的版本) 或.NET Core 类库的方式得
到实现。在评估 NuGet 包引用时,需要考虑它们所使用的.NET Standard 版本。如果它们
不能兼容任何.NET Standard 版本,也就不能兼容 .NET Core。
表1-1 所示为截至本书写作时的 .NET Standard、.NET Core 以及现有 .NET Framework 的
兼容性和版本对应关系( 表中数据来自微软官方文档)。
1.1.4 ASP.NET Core
ASP.NET Core 是一系列小的模块化组件,可添加到现有应用中,用于开发Web 应用和微服
务。ASP.NET Core 提供了路由、JSON 序列化、MVC控制器与视图的API。
在以前,ASP.NET 是 .NET Framework 的一部分——二者不可分离。在框架本身有了轻
量级与重量级之分之后( 即CLR拆分为两个版本),才能安装不包含 ASP.NET 的 .NET
Framework。
现在,与开源软件社区其他产品早已实现的模式一样,使用ASP.NET Core 也只需要添加
几个模块依赖,就可以把一个控制台应用转化为Web 应用或服务。与其他.NET Core 组件
一样,ASP.NET Core 也是100%开源的,它的源代码位于https://github.com/aspnet。
1.2 安装 .NET Core
前面已经提到,ASP.NET 现在不再需要安装了,因为它除了一些用于往 .NET Core 应用
添加功能的模块之外,再无其他。你需要安装的是 .NET Core 命令行工具,以及SDK。之
所以需要注意区分命令行工具与SDK,是因为我们可通过单一版本的命令行工具来安装
和管理多个 SDK( 例如,v1.0 和 v1.1)。
对于开源框架来说,这种新的模块化设计更加现代化,其他语言的各种框架也是这样管理
和发布的。对于从开源世界来到 .NET Core 的人来说,会对此感到自然而然。而对于曾经
的日常工作就是在一台台服务器上安装 ASP.NET 的开发人员来说,则是一种全新体验。
安装 .NET Core 的步骤,请参照其官方网站的说明。请安装最新版本的SDK(开发工具)
和最新版本的运行时。
对于不同的操作系统,安装说明有所不同;但安装完成后,应该都能成功运行下面的命令:
$ dotnet --version
1.0.3
你的版本号可能与上面的输出略有不同,但在安装后,dotnet 程序位置应该被添加到
PATH,并能成功输出版本号。本书基于 1.0.3 版的 SDK 以及 1.1.1 版的运行时编写的( 译
者注:截至本书中文版出版时,最新版的 .NET Core SDK 为 2.2.106,最新版的运行时为
2.2.4 版本。请关注官方网站了解最新的版本:https://dotnet.microsoft.com/download)。
.NET Core 社区十分活跃,发布节奏也很快,所以当你读到本书时,很可能开发工具和运
行时都有新版本了。
如果上面的命令没问题,你就有信心认为已经满足了在工作环境中安装 .NET Core 的基
本要求。按照微软的安装说明再检查一遍,以确保你已经安装了这些工具的最新版本。
本书所有的示例都假定项目由格式为.csproj 的项目文件管理。要注意的是,如果在网上
搜索示例代码,你可能会发现有些示例使用的是project.json 格式的项目文件。它们是过
去使用的格式,现在已经不再使用,与 1.x 版本的 SDK 已不再兼容。
如果遇到一个dotnet 命令的版本比上面的输出更早,就需要手动从GitHub 下载一个新
版本。
本书要求你的运行时版本为 1.1 或更高,而 SDK 开发工具的版本为 1.0.2 或更高。
.NET Core 模块化的一个副作用是,很多开发人员需要一段时间来适应这种 SDK( 开发工
具、CLI) 与运行时的版本号差异。在撰写本书时,最新的运行时版本是 1.1.1,在 Mac 上,
可使用以下命令来查看电脑上的所有运行时版本:
$ ls -F /usr/local/share/dotnet/shared/Microsoft.NETCore.App/
1.0.1/ 1.0.3/ 1.0.4/
1.1.0/ 1.1.0-preview1-001100-00/ 1.1.1/
如果在这个目录中能看到 1.1.1,而你使用 1.0.2 或更新版本的 SDK,那对于本书的后续
部分来说也是没有问题的。
如果在这个目录中没有看到 1.1.1,那就需要下载。在微软的.NET Core 页面上能直接找
到运行时的版本列表。
如果使用 Windows 机器,应该可在目录Program Files\dotnet\shared\Microsoft.NetCore.
App 找到已安装的运行时。
.NET Core 量级极轻,并且如前所述,只需要极少的必要条件就能运行。应用的所有依赖
都将借由dotnet restore 命令通过读取项目文件来下载。这对于云原生应用开发来说是必
备的特性,因为,如果要向云上部署不可变的发布物,就必须自主管理依赖( 随项目一起发
行)。在云环境,不应该对部署应用的虚拟机做任何假设。
1.3 开发控制台应用
在进入正式的讨论之前,我们需要确保能够创建、生成经典的简单范例程序——经常被嘲
笑却又无处不在的“Hello World”。
dotnet 命令行工具有一项功能,可用于创建简单的控制台应用的骨架结构代码。直接输入
dotnet new,不需要额外参数,它将向你展示包含所有可用模板的列表。在本例中,我们使
用console。
注意,上述命令会在当前目录创建项目文件。所以在运行该命令之前,先确保你当前已处
于期望的位置( 译者注:指将命令行环境的当前目录切换到正确的目录位置)。
$ dotnet new console
Welcome to .NET Core!
---------------------
Learn more about .NET Core @ https://aka.ms/dotnet-docs.
Use dotnet --help to see available commands or go to
https://aka.ms/dotnet-cli-docs.
Telemetry
--------------
The .NET Core tools collect usage data in order to improve your
experience.
The data is anonymous and does not include commandline arguments.
The data is collected by Microsoft and shared with the community.
You can opt out of telemetry by setting a DOTNET_CLI_TELEMETRY_OPTOUT
environment variable to 1 using your favorite shell.
You can read more about .NET Core tools telemetry @ https://aka.ms/
dotnet-cli-telemetry.
Configuring...
-------------------
A command is running to initially populate your local package cache, to
improve restore speed and enable offline access. This command will take up
to a minute to complete and will only happen once.
Decompressing 100% 2828 ms
Expanding 100% 4047 ms
Created new C# project in /Users/kevin/Code/DotNET/sample.
如果你之前运行过最新版的命令行工具,输出内容中的无用信息会少得多。注意上面的
输出中关于禁止采集的内容。如果你不希望微软以匿名方式收集你的编译习惯,可以在你
常用的 shell 或终端环境中修改配置,设置DOTNET_CLI_TELEMETRY_OPTOUT 为 1。
项目创建完成后,运行dotnet restore 可分析项目的依赖,并下载所有需要的包。每次在修
改项目文件后,都要执行这一步骤。
$ dotnet restore
Restoring packages for /Users/kevin/Code/DotNET/sample/sample.csproj...
Writing lock file to disk. Path: /Users/kevin/Code/DotNET/sample /obj/
project.assets.json
Restore completed in 743.6987ms for /Users/kevin/Code/DotNET/sample/
sample.csproj.
NuGet Config files used:
/Users/kevin/.nuget/NuGet/NuGet.Config
Feeds used:
https://api.nuget.org/v3/index.json
如果没有错误,运行应用之后就可在终端窗口看到“Hello World!”的输出了( 首次把应用
编译为二进制文件时,可能略有延迟)。
$ dotnet run
Hello World!
我们的项目包含两个文件:项目文件( 文件名默认为 < 目录名称>.csproj),以及 Program.
cs。代码清单 1-1 即为代码的内容。
代码清单1-1 Program.cs
using System;
namespace ConsoleApplication
{
class Program {
static void Main(string[] args){
Console.WriteLine(“Hello World!”);
}
}
}
在继续前,请确保你能成功运行上述所有dotnet 命令、执行应用并能看到正确的输出。表
面看来,这与此前版本的 .NET 控制台应用类似。接下来讨论 ASP.NET Core,很快我们就
能看到不同之处了。
查看 .csproj 项目文件,就会发现它声明了项目所面向的 netcoreapp 版本(1.0)。
为确保你的开发工具正常工作、环境适用于本书后续的所有示例代码( 使用v1.1 运行时版
本),我们需要编辑这个.csproj 文件。完成后,其内容应该为:
我们将其中的 .NET Core 版本升级到 1.1,同时依赖的 Microsoft.NETCore.App 的版本也
变成 1.1.0。现在就可以开始练习,有必要形成的一个习惯是,每次修改 .csproj 文件之后,
都需要运行一遍 dotnet restore。
$ dotnet restore
Restoring packages for /Users/kevin/Code/DotNET/sample/sample.csproj...
Generating MSBuild file /Users/kevin/Code/DotNET/sample/obj/ \ s ample.
csproj.nuget.g.props.
Writing lock file to disk. Path: /Users/kevin/Code/DotNET/sample /obj/ \
project.assets.json
Restore completed in 904.0985ms for /Users/kevin/Code/DotNET/sa mple/ \
sample.csproj.
NuGet Config files used:
/Users/kevin/.nuget/NuGet/NuGet.Config
Feeds used:
https://api.nuget.org/v3/index.json
现在,应该又可以再次运行应用了。视觉上应该没什么变化,也不会产生编译错误。
如果你一步步跟随练习下来,现在可查看 bin/Debug 目录,应该能发现两个子目录:一个
是 netcoreapp1.0,另一个是 netcoreapp1.1。这是因为刚才我们将应用分别面向两个目
标框架进行了编译。如果刚才先删了 bin 目录,再运行restore 和run 命令,就只会出现
netcoreapp1.1 目录。
1.4 开发第一个 ASP.NET Core 应用
往控制台应用添加 ASP.NET Core 功能实际上相当简单。新的 ASP.NET 项目,既可以用
Visual Studio 里的项目模板创建,也可以在 Mac 上用 Yeoman 创建。
不过,这里想向你展示,从一个Hello World 控制台应用到一个基于 Web 的HelloWorld,
即使不使用项目模板、脚手架工具,也是何等的轻而易举! 我的观点是,项目模板、脚手架
工具和操作向导都很有帮助,不过如果一个框架依赖于这些工具,那它在复杂度方面给人
们的压力就太大了。我有一个最喜欢的经验:
如果一个框架不能基于简易的文本编辑器和命令行工具来构建应用,就不是好框架。
1.4.1 向项目添加 ASP.NET 包
首先,我们需要往项目添加一些包引用:
• Microsoft.AspNetCore.Mvc
• Microsoft.AspNetCore.Server.Kestrel
• Microsoft.Extensions.Logging( 三个不同的包)
• Microsoft.Extensions.Configuration.CommandLine
添加引用时,既可以自行编辑项目文件,也可以使用 Visual Studio 或 VSCode 来添加。
在 .NET Core 早期,项目文件的格式曾发生过变化。从早期的 alpha 版本到预发布版本,
直到 1.0 的正式版都使用一个称为 project.json 的项目文件。在 1.0 版的开发工具包的
preview3 版本里,微软开发了跨平台版本的 MSBuild 工具,并内置于命令行工具中。接
着,在本书付印时,我们终于可以用上这种新的 MSBuild 格式的
件了。
下面是hellobook.csproj 文件的内容,其中包含新添加的依赖:
Version="1.1.1”/>
1.4.2 添加 Kestrel 服务器
我们从上面现成的示例程序上直接扩展,以针对每个收到的 HTTP 请求,都给出Hello
World 响应。不管请求什么 URL,使用哪种 HTTP 方法,都返回相同的响应。
下面的代码清单 1-2 即为更改后的程序入口文件 Program.cs。
代码清单1-2 Program.cs
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup
.UseConfiguration(config)
.Build();
host.Run();
}
}
}
在这个新的Main 方法里,我们首先初始化了配置子系统。ConfigurationBuilder 可用于从
JSON 文件、环境变量以及命令行参数( 如上所示) 读取配置。后面的示例中还会展示配
置系统的更多不同用法。
完成配置生成之后,我们使用WebHostBuilder 来设置 Web 宿主程序。我们不再使用
Windows 上的IIS(Internet Information Services, 因特网信息服务) 或者HWC(Hostable
Web Core, 可宿主 Web 核心) 了,取而代之的是,现在用一款称为 Kestrel 的跨平台、自宿
主的 Web 服务器。对于 ASP.NET Core 应用,即使部署到 Windows 平台的 IIS,在底层仍
使用 Kestrel 服务器。
1.4.3 添加启动类和中间件
在经典的 ASP.NET 中,我们用 global.asax.cs 文件完成应用启动期间各个阶段的工作。在
ASP.NET Core 中,可使用UserStartup<>泛型方法定义一个启动类,以新的方式处理启动
事件。
启动类支持以下这些方法( 译者注:这些方法并不是必须要声明,可按实际需要声明。详
情可参考 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup):
• 接收IHostingEnvironment 变量的构造函数。
• Configure 方法,用于配置 HTTP 请求管线,以及应用本身。
• ConfigureServices 方法,用于向系统添加具有特定作用域的服务,这些服务可通
过依赖注入使用。
代码清单1-2 里已经暗示,我们需要往项目里添加一个Startup 类,代码清单1-3 所示就是
这个类。
代码清单1-3 Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
namespace HelloWorld {
public class Startup
{
public Startup(IHostingEnvironment env)
{
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.Run(async(context)=>
{
await context.Response.WriteAsync(“Hello, World!”);
});
}
}
}
可用Use 方法向 HTTP 请求处理管线中添加中间件。在ASP.NET Core 中,一切都是可配
置、模块化的组件,并且具有极好的可扩展性。这得益于大范围地采用了中间件模式,这
一模式在其他语言的框架里也广泛采用。用其他开源框架开发过 Web 服务和应用的开发
人员可能对中间件概念已经很熟悉了。
ASP.NET Core 的中间件组件( 请求处理程序) 链在一起成为一个管线(Pipeline),在请求期
间,它们的处理逻辑按顺序被调用。正在运行的中间件需要负责调用排在后面的组件,或
者根据需要终止管线。
代码清单1-3 展示了一个尽可能简单的 ASP.NET 应用,它只有一个中间件组件,这个组件
处理所有请求。
可使用以下三种方法向请求处理过程添加中间件组件。
Map
通过Map 方法,可将特定路径映射到处理程序上,从而让请求管线拥有了分支处理能力。
我们还可以用MapWhen方法来获得更强大的功能,它支持基于条件判定的分支处理。
Use
Use 用于向管线中添加中间件组件。组件的代码需要决定要终止管线还是要继续执行管线。
Run
第一个用 Run 添加到管线里的中间件组件会让管线终止。如果用 Use 向管线里添加一个
组件,而这个组件不再调用下一个组件,就会导致管线终止,也就与 Run 的效果相同了。
后续章节会频繁地提及中间件组件。前面已经提到,这种以模块方式操作 “HTTP 请求处
理管线”的能力是编写强大微服务的关键。
1.4.4 运行应用
在命令行中运行dotnet run 即可启动示例应用。应用运行后,应该可看到如下输出。在运
行前,记得要先运行dotnet restore:
$ dotnet run
Hosting environment: Production
Content root path:
/Users/kevin/Code/DotNET/sample/bin/Debug/netcoreapp1.1
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
用下面的终端命令就能很容易地对这个服务进行测试。可以注意到,不管用什么URL,只
要curl 命令能识别,就都能调用中间件,并获得响应:
$ curl localhost:5000
Hello, World!
$ curl localhost:5000/will/any/url/work?
Hello, World!
Windows 没有内置 curl 命令。如果你使用 Windows 10 并启用了 Linux 子系统功能,就
可以在 Windows 上通过 bash 命令行窗口运行 curl。不然,也可以直接用浏览器打开对应
的 URL,或用你惯用的 REST 客户端测试工具,例如基于 Chrome 插件的 Postman。
如果在阅读本章期间,你没有随同上面的练习一步步输入代码,也可以从GitHub 库下载
完整的代码。
1.5 本章小结
在本章,我们开始了对 .NET Core 的学习。我们下载并安装最新版本的开发工具( 尽管开
发工具和运行时的版本差异容易弄混),然后创建了一个控制台应用。
接着用一个对所有请求都返回“Hello World”的中间件把这个控制台应用变成一个简单
的 Web 应用。这个过程很容易,只需要对项目文件做几处修改,再加几行代码就可以了。
如果目前还不能完全理解所有代码也不必担心;接下来的章节会探讨更多细节,到时候会
更加清晰。
到这里,你应该已经拥有了本书后续章节所需的大部分工具,为深入学习做好了准备!
想了解更多关于《ASP.NET Core微服务实战 在云环境中开发、测试和部署跨平台服务》内容,
请点击:https://item.jd.com/12611071.html