本系列代码全部采用.NET 6.0
ASP.NET Core应用
注册服务器与中间件
- 从应用承载或寄宿(Hosting)方面看,.NET Core具有一个以IHost/IHostBuilder为核心的服务承载系统。任何需要长时间运行的操作都可以定义成IHostedService服务并通过该系统来承载。
- IHost对象可以视为所有承载服务的宿主(Host),IHostBuilder对象则是它的构造者(Builder)。
一个ASP.NET Core应用本质上就是一个用来监听、接收和处理HTTP请求的后台服务,所以它被定义为一个GenericWebHostService(实现了IHostedService接口),并将它注册到承载系统中,进而实现了针对ASP.NET Core应用的承载。
1. 服务类型
ASP.NET Core提供了几种原生的服务类型:
-
```
(2)主程序文件
```csharp using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting;
Host.CreateDefaultBuilder() .ConfigureWebHost(builder => //构建管道->针对管道的配置 { builder.UseKestrel(); //将KestrelServer注册为服务器 //注册用来处理请求的中间件 builder.Configure(app => { app.Run(context => context.Response.WriteAsync(“Hello World”)); }); }).Build().Run();
- 调用静态类型`Host`的`CreateDefaultBuilder`方法创建了一个`IHostBuilder`对象,并最终调用该对象的`Build`方法构建作为服务宿主的`IHost`对象。当调用`IHost`对象的`Run`扩展方法时,ASP.NET Core应用程序将会被启动。
- 在`Build`方法调用之前,可以先调用`IHostBuilder`接口的`ConfigureWebHost`扩展方法,并利用指定的`Action<IWebHostBuilder>`委托对象**构建**ASP.NET Core应用的**请求处理管道**。
- 在管道配置中,调用`IWebHostBuilder`接口的`UseKestrel`扩展方法将`KestrelServer`注册为服务器。
- 在管道配置中,调用`Configure`扩展方法注册用来处理请求的中间件。扩展方法的输入参数时一`Action<IApplicationBuilder>`对象,所需的中间件注册在`IApplicationBuilder`对象上。
- 在中间件配置中,调用`IApplicationBuilder`接口的`Run`扩展方法注册了一个中间件。该中间件利用指定的`Func<HttpContext, Task>`对象将响应的主题内容设置为"Hello World"。
<a name="GyMcn"></a>
### 3. LaunchSettings.json
<a name="QC3Km"></a>
#### (1)修改SDK
- 每个.NET Core应用都针对一种具体的SDK类型。在项目文件中的`<Project Sdk="">`根节点设置了当前项目采用的SDK类型。
- 控制台应用默认采用的SDK类型为"Microsoft.NET.Sdk",而ASP.NET Core应用通常采用另一种名为"Microsoft.NET.Sdk.Web"的SDK类型。在这种类型下,可以将"Microsoft.AspNetCore.App"的框架引用从项目文件中删除。
```xml
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
重新编译后,会生成/Properties/launchSettings.json文件。
(2)lunchSettings.json文件说明
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:60646/", "sslPort": 44332 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "helloworld": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:5001;http://localhost:5000" } } }
其中,
iisSettings
节点用于设置IIS相关的选项,而profiles
节点定义了一系列用于描述应用启动场景的Profile。- 初始的文件会创建两个Profile,一个被命名为”IIS Express”,另一个则使用应用名称命名。每个Profile相当于定义了应用的启动场景,相关的设置包括应用启动的方式、环境变量和URL等,具体包含:
- commandName:
- 启动当前应用程序的命令类型,有效的选项包括IIS、IISExpress、Executable和Project
- executablePath:
- 如果commandName被设置为Executable,就需要利用该属性设置启动可执行文件的路径(绝对路径或相对路径)
- environmentVariables:
- 该属性用来设置环境变量。由于lanuchSettings.json文件仅仅在开发环境中使用,所以默认会添加一个名为”ASPNETCORE_ENVIRONMENT”的环境变量,并将它的值设置为”Development”用以表示当前部署环境
- commandLineArgs:
- 命令行参数,即传入Main方法的参数列表
- workingDirectory:
- 工作目录的绝对路径
- applicationUrl:
- 应用程序采用的URL列表,多个URL直接用分号( ; )进行分隔
- launchBrowser:
- 布尔类型的开关,表示应用程序启动时是否自动启动浏览器
- launchUrl:
- 如果launchBrowser被设置为True,浏览器采用的初始化路径就通过该属性进行设置
- nativeDebugging:
- 是否启动本地代码调试,默认值为False
- externalUrlConfiguration:
- 如果该属性设置为True,意味着禁用本地的配置,默认值为False
- use64Bit:
- 如果commandName属性被设置为IIS Express,该属性将决定采用X64版本还是X86版本,默认值为False,意味着ASP.NET Core应用默认采用X86版本的IIS Express
- lunchSettings.json文件中的所有设置仅仅针对开发环境,在产品环境下不需要这个文件。应用发布后生成的文件列表也不包含该文件。
- 通过项目属性-Debug选项可用图形界面来设置该文件的相关内容。
- 如果commandName属性被设置为IIS Express,该属性将决定采用X64版本还是X86版本,默认值为False,意味着ASP.NET Core应用默认采用X86版本的IIS Express
- commandName:
4. 显式指定URL
- 如果既不使用launchSettings.json文件中定义的URL,也不是有KestrelServer默认采用的监听地址,可以在应用程序中显式指定应用的URL。只需在管道配置中添加如下代码:
```csharp
Host.CreateDefaultBuilder()
.ConfigureWebHost(builder => //构建管道-》针对管道的配置
{
builder.UseKestrel(); //将KestrelServer注册为服务器
- builder.UseUrls(“http://localhost:5010;https://localhost:5011“);
//注册用来处理请求的中间件
builder.Configure(app =>
{
}); }).Build().Run(); ```app.Run(context => context.Response.WriteAsync("Hello World"));
5. ConfigureWebHostDefault
- 对于上面的
.ConfigureWebHost
管道配置方法,可以使用ConfigureWebHostDefault
方法替代,它会做一些默认设置,如:KestrelServer无需显式注册。具体详见13章。 - 使用
.ConfigureWebHost
时无法用IIS Express访问。
ASP.NET Core MVC应用
- 由于ASP.NET Core框架在本质上就是由服务器和中间件构建的消息处理管道,所以在它上面构建的应用开发框架都建立在某种类型的中间件上。
- 整个ASP.NET Core MVC开发框架就是建立在用来实现路由的EndpointRoutingMiddleware中间件和EndpointMiddleware中间件上的。
ASP.NET Core MVC利用路由系统为它分发请求,并在此基础上实现针对目标Controller的激活、Action方法的选择和执行,以及最终对于执行结果的响应。
注册服务与中间件
整个框架建立在EndpointRoutingMiddleware和EndpointMiddleware中间件构建的路由系统上。这两个中间件采用”终结点(Endpoint)映射”的方式实现针对HTTP请求的路由。
- 这里所谓的终结点可以视为应用程序提供的针对HTTP请求的处理器。这两个中间件通过预先设置的规则将具有某些特征的请求(如路径、HTTP方法等)映射到对应的终结点,进而实现路由的功能。
对于一个MVC应用程序来说,定义在Controller类型中的Action方法可以视为一个终结点,路由映射最终体现在HTTP请求与目标Action方法的映射上。
Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => //构建管道-》针对管道的配置 { builder.ConfigureServices(services => { services.AddRouting(); services.AddControllersWithViews(); }); //注册用来处理请求的中间件 builder.Configure(app => { app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); }); }).Build().Run();
在中间件配置中,先后调用IApplicationBuilder接口的UseRouting方法与UseEndpoints方法注册了EndpointRoutingMiddleware和EndpointMiddleware中间件。
- 在调用UseEndpoints方法时,利用指定的Action
委托对象调用了IEndpointRouteBuilder接口的MapControllers扩展方法,该方法完成了针对定义在Controller类型中所有Action方法的映射。 在.NET 6.0中的顶级语句中,可以直接使用app.MapControllers()来注册路由中间件,而不必使用app.UseRouting和app.UseEndpoints。
- 由于注册的中间件具有对相关服务的依赖,故需预先将这些服务注册到依赖注入框架中。
依赖服务的注册是通过调用IWebHostBuilder接口的ConfigureServices方法完成的。该方法参数类型为Action
,添加的服务注册就保存在IServiceCollection接口的集合中。 注册Startup类型
任何一个ASP.NET Core应用在初始化时都会根据请求处理的需求注册对应的中间件。在大部分真实的开发场景中,一般将中间件及以来服务的注册定义在一个单独的类中。按照约定,通常命名为Startup:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddRouting(); services.AddControllersWithViews(); } public void Configure(IApplicationBuilder app) { app.UseRouting(); app.UseEndpoints(endpoints => endpoints.MapControllers()); } }
由于已经将两种核心操作转移到Startup类中,故此时需要注册该类型。
- 通过调用IWebHostBuilder接口的UseStartup
扩展方法进行注册: Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => //构建管道-》针对管道的配置 { builder.UseStartup<Startup>(); }).Build().Run();