本章要点
- 创建第一个ASP.NET Core web应用程序
- 运行应用程序
- 了解应用程序的组件
读完第1章后,您应该对ASP.NET Core应用程序的工作原理以及何时使用它们有了大致的了解。您还应该设置了一个开发环境,可以用来开始构建应用程序。
提示:有关安装.NET 5.0 SDK和选择编辑器/IDE的指南,请参阅附录A。
在本章中,您将通过创建第一个web应用程序来深入了解并感受一下它是如何工作的。在后面的章节中,我将向你展示如何定制和构建自己的应用程序。
在完成本章的工作时,您应该开始掌握构成ASP.NET Core应用程序的各种组件,并了解一般应用程序构建过程。您创建的大多数应用程序都将从类似的模板开始,因此尽快熟悉相关设置过程是一个不错的主意。
定义:模板提供构建应用程序所需的基本代码。您可以使用模板作为构建自己应用程序的起点。
我将首先向您展示如何使用Visual Studio模板之一创建基本ASP.NET Core应用程序。如果您使用的是其他工具,如.NET CLI,则可以使用类似的模板。在本章中,我将Visual Studio 2019和ASP.NET Core 5.0与.NET 5.0一起使用,但我也提供了使用.NET CLI的提示。
提示:您可以在本书的GitHub存储库中查看本章的应用程序代码,网址为https://github.com/andrewlock/asp-dot-net-core-in-action-2e。
创建应用程序后,我将向您展示如何恢复所有必要的依赖关系、编译应用程序并运行它以查看HTML输出。该应用程序在某些方面很简单,它只有两个不同的页面,但它将是一个完全配置的ASP.NET Core应用程序。
运行完应用程序后,下一步将是了解发生了什么!我们将学习ASP.NET Core应用程序的所有主要部分,了解如何配置web服务器、中间件管道和HTML生成等。在这个阶段我们将不详细介绍,但您将了解它们是如何协同工作以创建完整的应用程序的。
我们将从开始一个新项目时创建的大量文件开始,您将了解典型的ASP.NET Core应用程序是如何布局的。特别是,我将重点介绍Program.cs和Startup.cs文件。实际上,应用程序的整个配置都发生在这两个文件中,因此最好了解它们的用途和使用方式。您将看到如何为应用程序定义中间件管道,以及如何自定义它。
最后,您将看到应用程序如何响应请求生成HTML,并查看构成RazorPages端点的每个组件。您将看到它如何控制响应请求运行的代码,以及如何定义应为特定请求返回的HTML。
在这个阶段,如果你发现项目的某些部分令人困惑或复杂,不要担心;在阅读本书时,您将详细探究每一部分。在本章结束时,您应该基本了解ASP.NET Core应用程序是如何组合在一起的,从应用程序首次运行到生成响应。在开始之前,我们将回顾ASP.NET Core应用程序如何处理请求。
2.1 ASP.NET Core应用程序的简要概述
在第1章中,我描述了浏览器如何向服务器发出HTTP请求并接收响应,该响应用于在页面上呈现HTML。ASP.NET Core允许您根据请求的详细信息动态生成HTML,因此,例如,您可以根据当前登录的用户显示不同的数据。
假设您想创建一个web应用程序来显示有关您公司的信息。您可以创建一个简单的ASP.NET Core应用程序来实现这一点;稍后,您可以向应用程序添加动态功能。图2.1显示了应用程序如何处理应用程序中的页面请求。
图2.1 ASP.NET Core应用程序概述。ASP.NET Core应用程序从浏览器接收传入的HTTP请求。每个请求都传递到中间件管道,后者可能会对其进行修改,然后将其传递到管道末端的端点中间件以生成响应。响应通过中间件传递回服务器,最后传递到浏览器。从第1章的图1.8中,您应该对该图的大部分内容很熟悉;请求和响应、反向代理和ASP.NET Core web服务器都仍然存在,但您会注意到我已经扩展了ASP.NET Core应用程序本身,以显示中间件管道和端点中间件。这是应用程序中用于生成请求响应的主要自定义部分。
反向代理转发请求后的第一个调用端口是ASP.NET Core web服务器,这是默认的跨平台Kestrel服务器。Kestrel接收原始传入网络请求,并使用它生成一个HttpContext对象,应用程序的其余部分可以使用该对象。
HttpContext对象
ASP.NET Core web服务器构建的HttpContext被应用程序用作单个请求的存储盒。特定于此特定请求和后续响应的任何内容都可以与之关联并存储在其中。这可能包括请求的属性、特定于请求的服务、已加载的数据或发生的错误。web服务器用原始HTTP请求的详细信息和其他配置详细信息填充初始HttpContext,并将其传递给应用程序的其余部分。
注:Kestrel不是ASP.NET Core中唯一可用的HTTP服务器,但它是性能最高的,而且是跨平台的。我只会在全书中提到凯斯特尔。主要替代方案HTTP.sys仅在Windows上运行,不能与IIS一起使用。
Kestrel负责接收请求数据并构造请求的C#表示,但它不尝试直接生成响应。为此,Kestrel将HttpContext交给ASP.NET Core应用程序中的中间件管道。这是一系列组件,用于处理传入请求以执行常见操作,如日志记录、处理异常或提供静态文件。
注意:您将在下一章详细了解中间件管道。
中间件管道的末端是端点中间件。这个中间件负责调用生成最终响应的代码。在大多数应用程序中,将是MVC或RazorPages块。
RazorPages负责生成构成典型ASP.NET Core web应用程序页面的HTML。它们通常也是应用程序的大部分业务逻辑所在,调用各种服务以响应原始请求中包含的数据。并非每个应用程序都需要MVC或RazorPages块,但这通常是构建大多数向用户显示HTML的应用程序的方式。
注:我将在第4章中介绍RazorPages和MVC控制器,包括如何在它们之间进行选择。我在第7章和第8章中介绍了生成HTML。
大多数ASP.NET Core应用程序都遵循这个基本架构,本章中的示例也没有什么不同。首先,您将看到如何创建和运行应用程序,然后我们将查看代码如何与图2.1中的大纲相对应。不用再多说,让我们创建一个应用程序!
2.2 创建第一个ASP.NET Core应用程序
您可以根据所使用的工具和操作系统,以多种不同的方式开始使用ASP.NET Core构建应用程序。每一组工具都有稍微不同的模板,但它们有很多相似之处。本章中使用的示例基于Visual Studio 2019模板,但您可以很容易地使用.NET CLI或Visual Studio for Mac中的模板。
提醒:本章使用Visual Studio 2019和ASP.NET Core 5.0以及.NET 5.0。
启动和运行应用程序通常涉及四个基本步骤,我们将在本章中介绍这些步骤:
- 生成——从模板创建基础应用程序以开始。
- 还原——使用NuGet将所有包和依赖项还原到本地项目文件夹。
- 编译——应用程序并生成所有必要的中间代码。
- 运行——运行编译的应用程序。
Visual Studio和.NET CLI包含许多ASP.NET Core模板,用于构建不同类型的应用程序。例如:
- RazorPages web应用程序-RazorPage应用程序在服务器上生成HTML,并设计为用户可以直接在web浏览器中查看。
- MVC(模型-视图-控制器)应用程序-MVC应用程序与RazorPages应用程序相似,因为它们在服务器上生成HTML,并设计为用户可以直接在web浏览器中查看。他们使用传统的MVC控制器而不是RazorPages。
- Web API应用程序Web API应用以可供单页应用程序(SPA)和API使用的格式返回数据。它们通常与Angular和React.js等客户端应用程序或移动应用程序结合使用。
我们将在本书中介绍每种应用程序类型,但在本章中,我们将重点介绍RazorPages模板。
2.2.1 使用模板开始
使用模板可以快速启动并运行应用程序,自动配置许多基本部分。Visual Studio和.NET CLI都附带了许多用于构建web应用程序、控制台应用程序和类库的标准模板。
提示:在.NET中,项目是一个部署单元,它将被编译为.dll文件或可执行文件。每个单独的应用程序都是一个单独的项目。一个解决方案中可以同时构建和开发多个项目。
要创建第一个web应用程序,请打开Visual Studio并执行以下步骤:
1. 从启动屏幕中选择“创建新项目”,或从Visual Studio主屏幕中选择文件>新建>项目。
2. 从模板列表中,选择ASP.NET Core Web Application,确保选择C#语言模板,如图2.2所示。单击Next。
图2.2 新项目对话框。从右侧的列表中选择C#ASP.NET Core Web应用程序模板。下次创建新项目时,可以从左侧的最近模板列表中进行选择。
3. 在下一个屏幕上,输入项目名称、位置和解决方案名称,然后单击Create,如图2.3所示。例如,使用WebApplication1作为项目和解决方案的名称。
图2.3“配置新项目”对话框。要创建新的.NET 5.0应用程序,请从模板屏幕中选择ASP.NET Core Web应用程序。在下面的屏幕上,输入项目名称、位置和解决方案名称,然后单击“创建”。
4. 在以下屏幕上(图2.4):
– 确保已选择.NET Core。
– 选择ASP.NET Core 5.0。如果此选项不可用,请确保已安装.NET 5.0。有关配置环境的详细信息,请参阅附录A。
– 选择ASP.NET Core Web App以创建RazorPages Web应用程序。
– 确保未指定身份验证。在第14章中,您将学习如何将用户添加到应用程序。
– 确保选中了Configure for HTTPS。
– 确保未选中“启用Docker支持”。
– 单击“创建”。
图2.4 web应用程序模板屏幕。此屏幕位于“配置您的项目”对话框之后,允许您自定义将生成应用程序的模板。对于这个初学者项目,您将创建一个没有身份验证的RazorPages web应用程序。
5. 等待Visual Studio从模板生成应用程序。Visual Studio完成后,您将看到一个关于ASP.NET Core的介绍页面,您应该能够看到Visual Studio已经创建并向您的项目添加了许多文件,如图2.5所示。
图2.5 从模板创建新ASP.NET Core应用程序后的Visual Studio。解决方案资源管理器显示新创建的项目。介绍页面提供了有关ASP.NET Core的有用链接。
如果未使用Visual Studio,则可以使用.NET CLI创建类似的模板。创建文件夹以保存新项目。在文件夹(在Windows上)或终端会话(在Linux或macOS上)中打开PowerShell或cmd提示符,然后运行以下列表中的命令。
Listing 2.1 Creating a new RazorPage application with the .NET CLI
dotnet new sln -n WebApplication1 //Create a solution file called WebApplication1 in the current folder. dotnet new webapp -o WebApplication1 //Create a RazorPages project in a subfolder, WebApplication1. dotnet sln add WebApplication1 //Add the new project to the solution file.
无论您使用Visual Studio还是.NET CLI,现在都已具备构建和运行第一个ASP.NET Core应用程序所需的基本文件。
2.2.2 构建应用程序
此时,您已经拥有运行应用程序所需的大部分文件,但还剩下两个步骤。首先,您需要确保将项目使用的所有依赖项复制到本地目录,其次,您需要编译应用程序,以便它可以运行。
这些步骤中的第一步并不是绝对必要的,因为Visual Studio和.NET CLI在第一次创建项目时都会自动还原包,但最好了解情况。在2.0之前的.NET CLI早期版本中,您需要使用dotnet还原手动还原包。
您可以通过选择Build>Build Solution、使用快捷键Ctrl-Shift-B或从命令行运行dotnet Build来编译应用程序。如果您从Visual Studio构建,输出窗口将显示构建的进度,并且假设一切都很好,将编译您的应用程序,准备运行。
您还可以从Visual Studio中的包管理器控制台运行dotnet构建控制台命令。
提示:如果Visual Studio和.NET CLI工具检测到文件已更改,则在您运行应用程序时,它们将自动构建应用程序,因此您通常不需要自己明确执行此步骤。
NuGet包和.NET命令行界面
.NET 5.0跨平台开发的基本组件之一是.NET命令行界面(CLI)。这为创建、构建和运行.NET 5.0应用程序提供了几个基本命令。VisualStudio有效地自动调用这些,但如果使用不同的编辑器,也可以直接从命令行调用它们。开发过程中最常用的命令是
dotnet restore
dotnet build
dotnet run
这些命令中的每一个都应在项目文件夹中运行,并将单独对该项目执行。
大多数ASP.NET Core应用程序依赖于各种外部库,这些库通过NuGet包管理器进行管理。项目中列出了这些依赖项,但不包括库本身的文件。在构建和运行应用程序之前,需要确保项目文件夹中有每个依赖项的本地副本。第一个命令dotnet restore确保将应用程序的NuGet依赖项复制到项目文件夹中。
ASP.NET Core项目在项目的.csproj文件中列出其依赖项。这是一个XML文件,将每个依赖项作为PackageReference节点列出。当您运行dotnet还原时,它使用此文件来确定要下载哪些NuGet包并将其复制到项目文件夹。列出的任何依赖项都可以在应用程序中使用。
还原过程通常在构建或运行应用程序时隐式发生,但有时在连续集成构建管道中显式运行它会很有用。
您可以使用dotnet build编译应用程序。这将检查应用程序中的任何错误,如果没有问题,将生成可以使用dotnet运行的输出。
每个命令都包含许多可以修改其行为的开关。要查看可用命令的完整列表,请运行
dotnet --help
或查看特定命令的可用选项,例如,运行
dotnet new --help
2.3 运行web应用程序
您已经准备好运行第一个应用程序,有许多不同的方法可以实现。在Visual Studio中,您可以单击IIS Express旁边工具栏上的绿色箭头,也可以按F5快捷键。Visual Studio将使用适当的URL自动为您打开一个web浏览器窗口,一两秒钟后,您将看到全新的应用程序,如图2.6所示。或者,您可以使用dotnet run从命令行使用.NET CLI工具运行应用程序,并在web浏览器中手动打开URL,使用命令行上提供的地址。
图2.6新ASP.NET Core应用程序的主页。当您从Visual Studio运行它时,默认情况下,IIS Express会选择一个随机端口。如果您从命令行运行dotnet run,您的应用程序将在http://localhost:5000和https://localhost:5001.
提示:首次从Visual Studio运行应用程序时,将提示您安装开发证书。这样做可以确保您的浏览器不会显示有关无效证书的警告。2有关HTTPS证书的更多信息,请参阅第18章。(您可以在Windows和macOS上安装开发证书。有关在Linux上信任证书的说明,请参阅发行版的说明。并非所有浏览器(例如Mozilla Firefox)都使用证书存储,因此请遵循浏览器信任证书的指南。如果您仍有困难,请参阅http://mng.bz/1rmy.)
默认情况下,此页面显示一个简单的欢迎横幅和指向ASP.NET Core官方Microsoft文档的链接。页面顶部有两个链接:主页和隐私。Home链接是您当前所在的页面。单击Privacy将转到一个新页面,如图2.7所示。不久您将看到,您可以在应用程序中使用RazorPages来定义这两个页面并构建它们显示的HTML。
图2.7 应用程序的Privacy页面。您可以使用应用程序标题中的Home和Privacy链接在应用程序的两个页面之间导航。该应用程序使用RazorPages生成页面内容。
在这一点上,你需要注意一些事情。首先,包含链接和应用程序标题“WebApplication1”的标题在两个页面上是相同的。第二,页面的标题(如浏览器的选项卡中所示)将更改以匹配当前页面。在第7章中,当我们讨论使用Razor模板对HTML进行排序时,您将看到如何实现这些功能。
注:您只能在当前运行该应用程序的同一台计算机上查看该应用程序;您的应用程序尚未暴露在互联网上。您将在第16章中学习如何发布和部署应用程序。
在这个阶段,应用程序的用户体验没有任何变化。单击一下,一旦你对应用程序的行为感到满意,卷起袖子,是时候看看一些代码了!
2.4 了解项目布局
当您刚接触框架时,从这样的模板创建应用程序可能是一件喜忧参半的事情。一方面,您可以快速启动并运行应用程序,而无需输入任何信息。相反,文件的数量有时会让人应接不暇,让你绞尽脑汁想从哪里开始。基本的web应用程序模板不包含大量的文件和文件夹,如图2.8所示,但我将详细介绍主要的模板,以使您了解方向。
图2.8 新ASP.NET Core应用程序的解决方案浏览器和磁盘上的文件夹。解决方案资源管理器还显示“连接的服务”和“依赖项”节点,其中列出了NuGet和其他依赖项,尽管磁盘上不存在文件夹本身。
首先要注意的是,主项目WebApplication1嵌套在具有解决方案名称的顶层目录中,在本例中也是WebApplication1。在这个顶级文件夹中,您还可以找到Visual Studio使用的解决方案(.sln)文件以及与Git版本控制相关的文件,尽管这些文件隐藏在Visual Studio的解决方案资源管理器视图中。
注意:Visual Studio使用解决方案的概念来处理多个项目。示例解决方案仅由.sln文件中列出的单个项目组成。如果使用CLI模板创建项目,则不会有.sln或Git文件,除非使用其他.NET CLI模板显式生成它们。
在解决方案文件夹中,您将找到项目文件夹,该文件夹依次包含三个子文件夹Pages、Properties和wwwroot。Pages(毫不奇怪)包含用于构建应用程序的RazorPages文件。Properties文件夹包含一个文件launchSettings.json,它控制Visual Studio如何运行和调试应用程序。wwwroot文件夹很特殊,因为它是应用程序中唯一允许浏览器在浏览web应用程序时直接访问的文件夹。您可以将CSS、JavaScript、图像或静态HTML文件存储在此处,浏览器将能够访问它们。他们将无法访问wwwroot之外的任何文件。
虽然wwwroot和Properties文件夹存在于磁盘上,但您可以看到Solution Explorer将它们显示为特殊节点,按字母顺序排列,位于项目顶部附近。项目中还有两个特殊节点,即Dependencies和Connected Services,但它们在磁盘上没有相应的文件夹。相反,它们显示了项目所依赖的所有依赖项的集合,例如NuGet包和远程服务。
在项目文件夹的根目录中,您将找到两个JSON文件:appsettings.json和appsettings.Development.json。这些提供了在运行时用于控制应用程序行为的配置设置。
项目中最重要的文件是WebApplication1.csproj,因为它描述了如何构建项目。Visual Studio没有显式显示.csproj文件,但如果在解决方案资源管理器中双击项目名称,则可以对其进行编辑。我们将在下一节中详细了解这个项目文件。
最后,Visual Studio在项目文件夹Program.cs和Startup.cs中显示了两个C#文件。在第2.6节和第2.7节中,您将看到这些基本类如何负责配置和运行应用程序。
2.5 .csproj项目文件:定义依赖项
.csproj文件是.NET应用程序的项目文件,包含.NET工具构建项目所需的详细信息。它定义了正在构建的项目类型(web应用程序、控制台应用程序或库)、项目目标平台(.NET Core 3.1、.NET 5.0等)以及项目所依赖的NuGet包。
该项目文件一直是.NET应用程序的主流,但在ASP.NET Core中,它进行了一次改版,使其更易于阅读和编辑。这些变化包括
- No GUID——以前,全局唯一标识符(GUID)用于许多事情,但现在很少在项目文件中使用。
- Implicit file includes——以前,项目中的每个文件都必须列在.csproj文件中,才能包含在构建中。现在,文件被自动编译。
- No paths to NuGet package .dll files——以前,您必须在.csproj中包含NuGet包中包含的.dll文件的路径,并在包中列出depen-dencies。配置文件。现在,您可以直接在.csproj中引用NuGet包,而不需要指定磁盘上的路径。
所有这些更改结合在一起,使项目文件比以前的.NET项目更加紧凑。下面的列表显示了示例应用程序的整个.csproj文件。
Listing 2.2 The .csproj project file, showing SDK, target framework, and references <Project Sdk="Microsoft.NET.Sdk.Web"> //The SDK attribute specifies the type of project you’re building. <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> </Project> //The TargetFramework is the framework you’ll run on, in this case, .NET 5.0.
对于简单的应用程序,您可能不需要太多地更改项目文件。Project元素上的Sdk属性包括描述如何构建项目的默认设置,而TargetFramework元素描述应用程序将在其上运行的框架。对于.NET Core 3.1项目,这将具有netcore-app3.1值;如果您在.NET 5.0上运行,则这将是net5.0。
提示:使用新的csproj样式,Visual Studio用户可以在解决方案资源管理器中双击项目以编辑.csproj文件,而无需先关闭项目。
您将对项目文件进行的最常见更改是使用PackageReference元素添加其他NuGet包。默认情况下,您的应用程序根本不引用任何NuGet包。
在项目中使用NuGet库
尽管所有应用程序在某些方面都是独一无二的,但它们也有共同的需求。例如,大多数应用程序需要访问数据库或为格式化数据处理JSON或XML。您应该使用现有的可重用库,而不是在每个项目中重新创建代码。
NuGet是.NET的库包管理器,其中库被打包到NuGet包中并发布到https://nuget.org.通过引用.csproj文件中的唯一包名,可以在项目中使用这些包。这些使包的命名空间和类在代码文件中可用。您可以将NuGet包发布(并托管)到存储库,而不是https://nuget.org-参见https://docs.microsoft.com/nuget详细信息。
通过在项目文件夹中运行dotnet add package<packagename>,可以将NuGet引用添加到项目中。这将使用<PackageReference>节点更新项目文件,并恢复项目的NuGet包。例如,安装流行的Newtonsoft。Json图书馆,你会运行
dotnet add package Newtonsoft.Json
这将向项目文件中添加对库的最新版本的引用,如下图所示,并使Newtonsoft。Json命名空间在源代码文件中可用。
<Project Sdk=“Microsoft.NET.Sdk.Web”>
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include=“NewtonSoft.Json”版本=“12.0.3”/>
</ItemGroup>
<Project>
如果您使用的是Visual Studio,则可以通过右键单击解决方案名称或项目并选择“管理NuGet包”来使用NuGet包管理器管理包。
有趣的是,NuGet的发音没有得到官方认可。欢迎使用流行的“noo-get”或“掘金”风格,或者如果你觉得特别时髦,“noo-jay”!
与以前的版本相比,简化的项目文件格式更易于手动编辑,如果您是跨平台开发,这是非常好的。但如果您使用的是Visual Studio,则不必走这条路。您仍然可以使用GUI添加项目引用、排除文件、管理NuGet包等。Visual Studio将一如既往地更新项目文件本身。
提示:有关csproj格式更改的更多详细信息,请参阅http://mng.bz/PPGg.
项目文件定义了Visual Studio和.NET CLI构建应用程序所需的一切。一切都是,除了代码!在下一节中,我们将查看ASP.NET Core应用程序的入口点Program.cs类。
2.6 Program类:构建web主机
所有ASP.NET Core应用程序的启动方式与.NET控制台应用程序相同-使用Program.cs文件。该文件包含一个静态void Main函数,这是控制台应用程序的标准特性。此方法必须存在,并在启动web应用程序时调用。
提示:.NET 5.0和C#9引入了“顶级语句”,它隐式地创建了Main入口点。我在本书中没有使用顶级语句,但ASP.NET Core 5.0支持它们。有关详细信息,请参阅文档:http://mng.bz/JDaP.
在ASP.NET Core应用程序中,Main入口点用于构建和运行IHost实例,如以下列表所示,其中显示了默认的Program.cs文件。IHost是ASP.NET Core应用程序的核心,包含应用程序配置和侦听请求并发送响应的Kestrel服务器。
清单2.3 默认Program.cs文件配置并运行IWebHost
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args) //使用CreateHostBuilder方法创建IHostBuilder。
.Build() //从IHostBuilder生成并返回IHost的实例。
.Run(); //运行IHost并开始侦听请求并生成
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args) //使用默认配置创建IHostBuilder。
.ConfigureWebHostDefaults(webBuilder => //配置应用程序以使用Kestrel并侦听HTTP请求。
{
webBuilder.UseStartup<Startup>(); //Startup类定义了应用程序的大部分配置。
};
}
}
Main函数包含创建web服务器和开始侦听请求所需的所有基本初始化代码。它使用通过调用CreateDefaultBuilder创建的IHostBuilder来定义如何配置IHost,然后通过调用Build()来实例化IHost。
注意:您会发现这种使用构建器对象来配置复杂对象的模式在ASP.NET Core框架中重复出现。这是一种有用的技术,允许用户配置对象,将其创建延迟到所有配置完成。这是Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides(Addison Wesley,1994)在“Gang of Four”一书《Design Patterns: Elements of Reusable Object-Oriented Software》中描述的模式之一。
应用程序的大部分配置都是在调用CreateDefaultBuilder创建的IHostBuilder中进行的,但它将一些责任委托给了一个单独的类Startup。通用UseStartup<>方法中引用的Startup类是配置应用程序服务和定义中间件管道的地方。在第2.7节中,我们将花一段时间深入研究这一关键课程。
此时,您可能想知道为什么需要两个类进行配置:Program和Startup。为什么不在一个类或另一个类中包含应用程序的所有配置?
图2.9显示了Program和Startup之间配置组件的典型划分。一般来说,Program是配置应用程序基础结构的地方,例如HTTP服务器、与IIS的集成以及配置源。相反,Startup是定义应用程序使用的组件和功能以及应用程序的中间件管道的地方。
图2.9 Program和Startup配置范围的差异。项目关注的是在整个项目生命周期内通常保持稳定的基础设施配置。相反,您通常会修改Startup以添加新功能并更新应用程序行为。
两个不同ASP.NET Core应用程序的Program类通常是相似的,但Startup类通常会有很大的不同(尽管它们通常遵循相似的模式,稍后您将看到)。您很少会发现,随着应用程序的增长,您需要修改Program,而您通常会在添加其他功能时更新Startup。例如,如果您在项目中添加了新的NuGet依赖项,通常需要更新Startup以利用它。
Program类是进行大量应用程序配置的地方,但在默认模板中,这隐藏在CreateDefaultBuilder方法中。CreateDefaultBuilder是一个静态帮助器方法,它通过使用一些常见配置创建IHostBuilder来简化应用程序的引导。在第11章中,我们将深入了解此方法并探索配置系统,但现在只需记住图2.9,并注意如果需要,您可以完全更改IHost配置。
默认情况下使用的另一个Helper方法是ConfigureWebHostDefaults。这使用WebHostBuilder对象来配置Kestrel以侦听HTTP请求。
使用通用主机创建服务
您必须同时调用ConfigureWebHostDefaults和CreateDefaultBuilder,这可能看起来很奇怪。难道我们只有一个方法吗?处理HTTP请求不是ASP.NET Core的全部目的吗?
好吧,是的,也不是!ASP.NET Core 3.0引入了通用主机的概念。这允许您使用与ASP.NET Core应用程序相同的框架来编写非HTTP应用程序。例如,这些应用程序可以作为控制台应用程序运行,也可以作为Windows服务(或作为Linux上的systemd守护程序)安装,以运行后台任务或从消息队列读取。
Kestrel和ASP.NET Core的web框架建立在ASP.NET Core 3.0中引入的通用主机功能之上。要配置典型的ASP.NET Core应用程序,您需要配置所有应用程序通用的通用主机特性;配置、日志记录和依赖服务等功能。对于web应用程序,您还可以配置处理web请求所需的服务,如Kestrel。
在第22章中,您将看到如何使用通用主机构建应用程序以运行计划任务和构建服务。
一旦IHostBuilder的配置完成,对Build的调用将生成IHost实例,但应用程序仍然没有处理HTTP请求。调用Run启动HTTP服务器侦听。此时,您的应用程序已完全运行,可以响应来自远程浏览器的第一个请求。
2.7 Startup类:配置应用程序
正如您所看到的,Program负责为您的应用程序配置许多基础设施,但您需要在Startup中配置一些应用程序的行为。Startup类负责配置应用程序的两个主要方面:
- 服务注册——所有应用程序依赖的类(包括提供框架使用的功能和特定于应用程序的功能)都必须注册,以便在运行时正确实例化。
- 中间件和端点——应用程序如何处理和响应请求。
您可以在Startup中使用自己的方法配置每个方面:ConfigureServices中的服务注册,configure中的中间件配置。启动的典型概要如下所示。
清单2.4 Startup.cs的概要,显示如何配置每个方面
public class Startup
{
public void ConfigureServices(IServiceCollection services) //通过向IServiceCollection注册服务来配置服务。
{
// method details
}
public void Configure(IApplicationBuilder app) //配置用于处理HTTP请求的中间件管道。
{
// method details
}
}
Program中创建的IHostBuilder调用ConfigureServices,然后调用Configure,如图2.10所示。每个调用配置应用程序的不同部分,使其可用于后续方法调用。ConfigureServices方法中注册的任何服务都可用于Configure方法。配置完成后,通过调用IHostBuilder上的Build()来创建IHost。
图2.10 IHostBuilder在Program.cs中创建,并在启动时调用方法来配置应用程序的服务和中间件管道。配置完成后,通过调用IHostBuilder上的Build()来创建IHost。
Startup类的一个有趣之处是它没有实现这样的接口。相反,通过使用反射来调用这些方法,以查找具有预定义名称Configure和ConfigureServices的方法。这使类更加灵活,并允许您修改方法的签名以接受自动实现的其他参数。我将在第10章中详细介绍这是如何工作的;现在,只要知道ConfigureServices中配置的任何内容都可以通过Configure方法访问就足够了。
定义:.NET中的反射允许您在运行时获取有关应用程序中类型的信息。您可以使用反射在运行时创建类的实例,并调用和访问它们。
因为Startup类是ASP.NET Core应用程序的基础,所以第2.7节的其余部分将指导您完成ConfigureServices和Configure,让您了解如何使用它们。我不会详细解释它们(我们有本书的其余部分!),但是您应该记住它们是如何相互继承的,以及它们对整个应用程序配置的贡献。
2.7.1 添加和配置服务
ASP.NET Core为每个不同的功能使用小型模块化组件。这允许单独的功能单独发展,只与其他功能松散耦合,通常认为这是良好的设计实践。这种方法的缺点是,它给功能的使用者带来了正确实例化功能的负担。在应用程序中,这些模块化组件作为应用程序使用的一个或多个服务公开。
定义:在ASP.NET Core的上下文中,服务是指为应用程序提供功能的任何类。这些可能是您为应用程序编写的库或代码所公开的类。
例如,在电子商务应用程序中,您可能有一个TaxCalculator,它可以计算特定产品的应纳税额,同时考虑用户在世界上的位置。或者您可能有一个ShippingCostService,它计算运送到用户所在地的成本。第三个服务OrderTotalCalculatorService可能使用这两个服务来计算用户必须为订单支付的总价。每个服务都提供一小部分独立的功能,但您可以将它们组合起来创建一个完整的应用程序。这就是所谓的单一责任原则。
定义:单一责任原则(SRP)规定,每个类只应负责一部分功能,只有在所需功能发生变化时才需要更改。这是Robert C.Martin在《Agile Software Development, Principles, Patterns, and Practices》(Pearson,2013)中提出的五项主要设计原则之一。
OrderTotalCalculatorService需要访问ShippingCostService和TaxCalculator的实例。解决这个问题的一种简单方法是使用新关键字,并在需要时创建服务实例。不幸的是,这将您的代码与您正在使用的特定实现紧密结合,并可能会完全取消通过模块化功能实现的所有良好工作。在某些情况下,执行您创建的服务的初始化代码也可能破坏SRP。
解决这个问题的一个方法是让它成为别人的问题。在编写服务时,您可以声明依赖项,并让另一个类为您填充这些依赖项。然后,您的服务可以专注于它所设计的功能,而不是试图找出如何构建其依赖关系。
他的技术被称为依赖注入或控制反转(IoC)原理,这是一种被广泛使用的公认的设计模式。
定义:设计模式是常见软件设计问题的解决方案。
通常,您会将应用程序的依赖项注册到“容器”中,然后可以使用该容器创建任何服务。这对于您自己的自定义应用程序服务和ASP.NET Core使用的框架服务都是如此。您必须在容器中注册每个服务,然后才能在应用程序中使用它。
注:我将在第10章详细描述ASP.NET Core中使用的依赖反转原理和IoC容器。
在ASP.NET Core应用程序中,此注册是在ConfigureServices方法中执行的。每当您在应用程序中使用新的ASP.NET Core功能时,都需要返回此方法并添加必要的服务。这并不像听起来那么困难,如下面的列表(取自示例应用程序)所示。
清单2.5 Startup.ConfigureServices:向IoC容器添加服务
public class Startup
{
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}
}
您可能会惊讶于,一个完整的Razor Pages应用程序只包含一个添加必要服务的调用,但AddRazorPage()方法是一个扩展方法,它封装了设置Razor Pages服务所需的所有代码。在幕后,它添加了各种Razor服务,用于呈现HTML、格式化服务、路由服务等。
除了注册与框架相关的服务之外,此方法还可以注册应用程序中的任何自定义服务,例如前面讨论的示例TaxCalculator。IServiceCollection是应用程序需要使用的所有已知服务的列表。通过向其中添加新服务,可以确保每当类声明对服务的依赖时,IoC容器都知道如何提供它。
所有服务都已配置完毕,现在是时候进入最后一个配置步骤了:定义应用程序如何响应HTTP请求。
2.7.2 定义如何使用中间件处理请求
到目前为止,在IHostBuilder和Startup类中,您已经定义了应用程序的基础结构,并向IoC容器注册了服务。在Startup类的最后一个配置方法Configure中,您为应用程序定义中间件管道,该管道定义应用程序如何处理HTTP请求。下面是模板应用程序的Configure方法。
清单2.6 Startup.Configure:定义中间件管道
public class Startup
{
//IApplicationBuilder用于构建中间件管道。可以接受其他服务作为参数。
public void Configure( IApplicationBuilder app, IWebHostEnvironment env)
{
//开发或生产时的不同行为
if (env.IsDevelopment())
{
//仅在开发环境中运行
app.UseDeveloperExceptionPage();
}
else
{
//仅在生产环境中运行
app.UseExceptionHandler("/Error"); app.UseHsts();
}
app.UseHttpsRedirection();
//添加静态文件中间件
app.UseStaticFiles();
//添加端点路由中间件,该中间件决定要执行哪个端点
app.UseRouting();
//添加授权中间件,它可以根据需要阻止对特定页面的访问
app.UseAuthorization();
//添加端点中间件,该中间件执行RazorPage以生成HTML响应
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
}
}
}
如前所述,中间件由小组件组成,当应用程序接收到HTTP请求时,这些组件按顺序执行。它们可以执行一整套功能,例如日志记录、识别请求的当前用户、提供静态文件和处理错误。
传递给Configure方法的IApplicationBuilder用于定义中间件的执行顺序。此方法中调用的顺序很重要,因为它们添加到生成器的顺序就是它们在最终管道中执行的顺序。中间件只能在管道中使用以前的中间件创建的对象,而不能访问后来的中间件所创建的对象。
警告:在将中间件添加到管道中时,务必考虑中间件的顺序。中间件只能使用管道中早期中间件创建的对象。
您还应该注意,IWebHostEnvironment参数用于在开发环境中提供不同的行为。当您在开发中运行时(当EnvironmentName设置为“development”时),Configure方法将一个异常处理中间件添加到管道中;在生产中,它添加了一个不同的。
IWebHostEnvironment对象包含由程序中的IHostBuilder确定的当前环境的详细信息。它公开了许多属性:
- ContentRootPath——应用程序的工作目录的位置,通常是运行应用程序的文件夹
- WebRootPath——包含静态文件的wwwroot文件夹的位置
- EnvironmentName——当前环境是开发环境还是生产环境
IWebHostEnvironment在调用Startup时已设置;无法使用“Startup”中的应用程序设置更改这些值。EnvironmentName通常在应用程序启动时使用环境变量从外部设置。
注:您将在第11章中了解托管环境以及如何更改当前环境。
在开发中,DeveloperExceptionPageMiddleware(由UseDeveloperExcessionPage()调用添加)确保如果应用程序抛出未捕获的异常,浏览器中会显示尽可能多的信息来诊断问题,如图2.11所示,但这次是白色的,不是黄色的。
图2.11开发人员异常页面包含许多不同的信息源以帮助您诊断问题,包括异常堆栈跟踪和生成异常的请求的详细信息。
注意:默认模板也会在生产中添加HstsMiddleware,它会根据行业最佳实践在响应中设置安全标头。请参阅第18章,了解有关此和其他安全相关中间件的详细信息。
当您在生产环境中运行时,将大量数据暴露给用户将是一个巨大的安全风险。相反,ExceptionHandlerMiddleware是注册的,这样,如果用户在您的方法中遇到异常,将向他们显示一个友好的错误页面,该页面不会显示问题的来源。如果在生产模式下运行默认模板并触发错误,则将显示图2.12所示的消息。显然,您需要更新此页面以使其更具视觉吸引力和用户友好,但至少它不会揭示应用程序的内部工作方式。
添加到管道中的下一个中间件是HttpsDirectionMiddleware,使用以下语句:
app.UseHttpsRedirection();
这确保您的应用程序只响应安全(HTTPS)请求,是行业最佳做法。我们将在第18章中详细介绍HTTPS。
图2.12 默认异常处理页面。与开发人员异常页面不同的是,此页面不会向用户透露任何有关应用程序的详细信息。事实上,您可以将消息更新为更方便用户的内容。
StaticFileMiddleware将添加到管道中,接下来是以下语句:
app.UseStaticFiles();
他的中间件负责处理静态文件(如CSS文件、JavaScript文件和图像)的请求。当请求到达中间件时,它会检查该请求是否针对现有文件。如果是,中间件将返回文件。如果没有,则忽略该请求,下一个中间件可以尝试处理该请求。图2.13显示了在请求静态文件时如何处理请求。当静态文件中间件处理请求时,管道中稍后出现的其他中间件(如路由中间件或端点中间件)根本不会被调用。
图2.13 /css/site上的静态文件请求概述。css用于ASP.NET Core应用程序。请求通过中间件管道,直到由静态文件中间件处理。这将返回请求的CSS文件作为响应,并将其传递回web服务器。端点中间件从未被调用,也从未看到请求。
现在,我们来看看管道中最重要的中间件:路由中间件和端点中间件。这对中间件一起负责解释请求以确定要调用哪个Razor Page,从请求中读取参数,并生成最终的HTML。需要非常简单的配置,您只需要将中间件添加到管道中,并通过调用MapRazorPages指定您希望使用Razor Page端点。对于每个请求,路由中间件使用请求的URL来确定要调用哪个Razor Page。端点中间件实际上执行Razor Page以生成HTML响应。
注意:默认模板还将在路由中间件和端点中间件之间添加AuthorizationMiddleware。这允许身份验证中间件在执行RazorPage之前决定是否允许访问。您将在关于路由的第5章和关于授权的第15章中了解有关此方法的更多信息。
哈哈!您终于完成了应用程序所需的所有设置、服务和中间件的配置。配置应用程序涉及广泛的不同主题,我们将在本书中进一步深入讨论,因此如果您还没有完全理解所有步骤,请不要担心。
一旦配置了应用程序,它就可以开始处理请求。但它是如何处理它们的?我已经提到了StaticFileMiddleware,它将向用户提供图像和CSS文件,但是需要HTML响应的请求呢?在本章的其余部分,我将向您介绍Razor Pages及其如何生成HTML。
2.8 使用Razor Pages生成响应
当ASP.NET Core应用程序收到请求时,它通过中间件管道前进,直到中间件组件能够处理它,如图2.13所示。通常,管道中的最后一块中间件是端点中间件。该中间件与路由中间件一起工作,以将请求URL的路径匹配到已配置的路由,该路由定义要调用哪个Razor Page。
定义删除域后,路径是请求URL的剩余部分。例如,对于发送到www.microsoft.com/account/manage的请求,路径为/account/manage。
一旦选择了Razor Page,路由中间件就会在请求的HttpContext中记录所选的Razor Page,并继续执行中间件管道。最终,请求将到达端点中间件。端点中间件执行Razor Page以生成HTML响应并将其发送回浏览器,如图2.14所示。
图2.14 将Razor模板渲染为HTML。Razo rPage是基于URL页面/Privacy选择的,并被执行以生成HTML。
在下一节中,我们将研究Razor Pages如何使用Razor语法生成HTML。之后,我们将研究如何使用页面处理程序将业务逻辑和行为添加到Razor Pages。
2.8.1 使用Razor Page生成HTML
Razor Pages存储在项目Pages文件夹中的.cshtml文件(.cs和.html的组合)中。通常,路由中间件通过在项目的Pages文件夹中查找具有相同路径的Razor Page,将请求URL路径映射到单个RazorPage。例如,您可以在图2.14中看到,应用程序的Privacy页面对应于浏览器地址栏中的路径/Privacy。如果您查看项目的Pages文件夹,您会发现Privacy.cshtml文件,如以下列表所示。
清单2.7 Privacy.cshtml Razor页面
@page // 指示这是RazorPage
@model PrivacyModel // 将Razor Page链接到特定的PageModel
@{
ViewData["Title"] = "Privacy Policy"; // 不写入响应的C#代码
}
<h1>@ViewData["Title"]</h1> //将动态C#值写入响应的HTML
<p>Use this page to detail your site's privacy policy.</p> //独立的静态HTML
Razor Pages使用名为Razor的模板语法,将静态HTML与动态C#代码和HTML生成相结合。Razor Page第一行的@page指令是最重要的。该指令必须始终放在文件的第一行,因为它告诉ASP.NET Core .cshtml文件是RazorPage。如果没有它,您将无法正确查看页面。
Razor Page的下一行定义了Razor Page与项目中的哪个PageModel关联:
@model PrivacyModel
在这种情况下,PageModel被称为PrivacyModel,它遵循命名Razor Page模型的标准惯例。您可以在Privacy.cshtml中找到该文件,如图2.15所示。Visual Studio将这些文件嵌套在Solution Explorer中的RazorPage.cshtml文件下面。我们将在下一节中查看页面模型。
图2.15按照惯例,Razor Pages的页面模型放置在与RazorPage同名的文件中,并附加.cs后缀。Visual Studio将这些文件嵌套在解决方案资源管理器中的Razor Page下。
除了@page和@model指令之外,您可以看到静态HTML在RazorPage中始终有效,并将在响应中“原样”呈现。
<p>Use this page to detail your site’s privacy policy.</p>
您还可以使用以下构造在Razor模板中编写普通的C#代码:
@{ /* C# code here */ }
大括号之间的任何代码都将被执行,但不会写入响应。在列表中,您通过向ViewData字典写入关键字来设置页面标题,但此时没有向响应写入任何内容:
@{
ViewData["Title"] = "Privacy Policy";
}
此模板中显示的另一个特性是,您可以使用@符号将C#变量动态写入HTML流。这种结合动态和静态标记的能力正是Razor Pages的强大之处。在本例中,您从ViewData字典中获取“Title”值,并将这些值写入<h1>标记中的响应:
<h1>@ViewData["Title"]</h1>
此时,当与图2.14所示的输出进行比较时,您可能会对清单2.7中的模板感到有点困惑。列表和图中都显示了标题和静态HTML内容,但最终网页的某些部分没有显示在模板中。这怎么可能?
Razor Pages具有布局的概念,它是定义应用程序常见元素(如页眉和页脚)的“基本”模板。布局的HTML与RazorPage模板相结合,生成发送到浏览器的最终HTML。这防止了您必须在每个页面中复制页眉和页脚的代码,这意味着,如果您需要调整某些内容,您只需要在一个位置进行调整。
注:我将在第7章详细介绍Razor模板,包括布局。您可以在项目的Pages/Shared文件夹中找到布局。
正如您已经看到的,您可以通过使用花括号@{}在RazorPages中包含C#代码,但一般来说,您希望将.cshtml文件中的代码仅限于显示内容。复杂的逻辑、访问服务(如数据库)的代码和数据操作应该在PageModel中处理。
2.8.2 使用PageModel和处理程序处理请求逻辑
正如您已经看到的,.cshtml文件中的@page指令将页面标记为Razor Page,但大多数Razor Pages也有关联的页面模型。按照惯例,这被放置在一个通常称为“代码隐藏”文件的文件中,该文件具有.cs扩展名,如图2.15所示。页面模型应该派生自PageModel基类,它们通常包含一个或多个称为页面处理程序的方法,这些方法定义如何处理对Razor Page的请求。
定义:页面处理程序是响应请求而运行的方法。Razor Page模型必须从PageModel类派生。它们可以包含多个页面处理程序,但通常只包含一个或两个。
下面的列表显示了Privacy.cshtml RazorPage的页面模型,位于文件Privacy.cshtml.cs中。
清单2.8 Privacy中的PrivacyModel.cshtmlcs——RazorPage页面模型
//RazorPages必须继承自PageModel。
public class PrivacyModel: PageModel
{
private readonly ILogger<PrivacyModel> _logger;
//可以使用依赖注入在构造函数中提供服务。
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
//默认的页面处理程序是OnGet。返回void表示应生成HTML。
public void OnGet()
{
}
}
这个页面模型非常简单,但它展示了几个重要的点:
- 页面处理程序由约定驱动。
- 页面模型可以使用依赖注入与其他服务交互。
页面处理程序通常根据其响应的HTTP谓词按惯例命名。它们返回void(表示应呈现Razor Page的模板)或IActionResult(包含生成响应的其他指令,例如将用户重定向到其他页面)。
定义:每个HTTP请求都包含一个表示请求“类型”的动词。浏览网站时,默认动词是GET,它从服务器获取资源,以便您查看。第二个最常见的动词是POST,它用于向服务器发送数据,例如在完成表单时。
PrivacyModel包含一个处理程序OnGet,该处理程序指示它应该响应页面的GET请求而运行。当方法返回void时,执行处理程序将为页面执行关联的Razor模板以生成HTML。
注意:Razor Pages专注于构建基于页面的应用程序,因此您通常希望返回HTML而不是JSON或XML。但是,您也可以使用IActionResult返回任何类型的数据,将用户重定向到新页面,或发送错误。您将在第4章中了解有关IActionResults的更多信息。
依赖注入用于将ILogger<PrivacyModel>实例注入到页面模型的构造函数中。此示例中未使用该服务,但它可以用于将有用信息记录到各种目的地,例如控制台、文件或远程日志记录服务。您可以通过在构造函数中接受其他服务作为参数来访问页面模型中的其他服务。ASP.NET Core框架将负责配置和注入您请求的任何服务的实例。
注:我在第10章详细描述了ASP.NET Core中使用的依赖性反转原理和IoC容器。第17章介绍了日志记录。
显然,PrivacyModel页面模型在这种情况下做不了什么,您可能会想为什么值得拥有它。如果他们所做的只是告诉Razor Page生成HTML,那么我们为什么需要页面模型呢?
这里要记住的关键点是,您现在有了一个框架,可以响应请求执行任意复杂的功能。您可以很容易地更新handler方法以从数据库加载数据、发送电子邮件、将产品添加到购物篮或创建发票,所有这些都是响应简单的HTTP请求。这种可扩展性是Razor Pages(以及MVC模式)的强大之处。
另一个重要的点是,您将这些方法的执行与HTML本身的生成分离开来。如果逻辑发生变化,并且需要向页面处理程序添加行为,则不需要修改HTML生成代码,因此不太可能引入错误。相反,如果需要稍微更改UI,例如更改标题的颜色,则处理程序方法逻辑是安全的。
这就是一个完整的ASP.NET Core Razor Pages应用程序!在继续之前,让我们最后看一下应用程序如何处理请求。图2.16显示了示例应用程序正在处理的对/隐私路径的请求。您已经看到了这里的所有内容,因此处理请求的过程应该很熟悉。它显示了请求在被端点中间件处理之前如何通过中间件管道。Privacy.cshtml RazorPage执行OnGet处理程序并生成HTML响应,该响应在发送到用户浏览器之前通过中间件传递回ASP.NET Core web服务器。
这是一次非常紧张的旅程,但现在您可以很好地了解整个应用程序是如何配置的,以及它如何使用RazorPages处理请求。在下一章中,您将进一步了解所有ASP.NET Core应用程序中存在的中间件管道。您将了解它是如何组成的,如何使用它为应用程序添加功能,以及如何使用它创建简单的HTTP服务。
图2.16示例ASP.NET RazorPages应用程序的/Privacy URL请求概述。路由中间件将请求路由到Privacy.cshtml.cs RazorPage的OnGet处理程序。RazorPage通过在Privacy.cshtml中执行Razor模板生成HTML响应,并通过中间件管道将响应传递回浏览器。
总结
- .csproj文件包含如何构建项目的详细信息,包括它所依赖的NuGet包。Visual Studio和.NET CLI使用它来构建应用程序。
- 恢复ASP.NET Core应用程序的NuGet包将下载项目的所有依赖项,以便可以构建和运行。
- Programcs定义应用程序的静态void Main入口点。此功能在应用程序启动时运行,与控制台应用程序相同。
- Programcs是使用IHostBuilder构建IHost实例的地方。助手方法HostCreateDefaultBuilder()创建一个IHostBuilder,用于加载配置设置并设置日志记录。调用Build()将创建IHost实例。
- ConfigureWebHostDefaults扩展方法使用WebHostBuilder配置通用主机。它配置Kestrel HTTP服务器,必要时添加IIS集成,并指定应用程序的Startup类。
- 您可以通过在IHost上调用Run来启动web服务器并开始接受HTTP请求。
- Startup负责服务配置和定义中间件管道。
- 所有服务(包括框架服务和自定义应用程序服务)必须在ConfigureServices调用中注册,以便稍后在应用程序中访问。
- 中间件通过IApplicationBuilder添加到应用程序管道中。中间件定义应用程序如何响应请求。
- 中间件的注册顺序定义了应用程序中间件管道的最终顺序。通常,EndpointMiddleware是管道中的最后一个中间件。早期的中间件,如StaticFileMiddle-ware,将尝试首先处理请求。如果处理了请求,EndpointMiddleware将永远不会接收到请求。
- Razor Pages位于Pages文件夹中,通常根据其处理的URL路径命名。例如,Privacy.cshtml处理路径/Privacy。
- Razor Pages必须包含@page指令作为文件的第一行。
- 页面模型派生自PageModel基类并包含页面处理程序。页面处理程序是使用指示其处理的HTTP谓词的约定命名的方法。例如,OnGet处理GET动词。
- Razor模板可以包含独立的C#、独立的HTML和从C#值生成的动态HTML。通过将这三者结合起来,您可以构建高度动态的应用程序。
- Razor布局定义网页的常见元素,如页眉和页脚。它们允许您将此代码提取到一个文件中,因此您不必在每个Razor模板中复制它。
标签:Core,ASP,请求,中间件,应用程序,Action,NET From: https://www.cnblogs.com/SoftwareLife/p/16944090.html