本文内容适用于ASP.NET Core 5.0
“启动” 类
启动 类用于配置应用程序依赖的 服务(services) 和用于处理客户端http请求的 流水线(pipeline)
ASP.NET Core 应用程序使用 启动 类(这个 类 按照约定命名为 Startup
)完成如下启动任务:
- [可选]
Startup
类包括一个ConfigureServices
方法用于配置应用程序依赖的 服务(services) , 服务 是为应用程序提供某项功能的可重用组件。 服务 通过ConfigureServices
方法进行注册,注册后的服务全局可用,使用的方式是通过 依赖注入(DI) 或ApplicationServices
。 - Startup 类包括一个 Configure 方法,此方法用于创建处理客户端http请求的 流水线(pipeline)
Startup
类的 ConfigureServices
方法和 Configure
方法在应用程序启动时被ASP.NET Core 运行时调用:
1 | public class Startup |
上面的代码针对的是 Razor Pages 编程框架,使用 MVC 框架的代码和这段代码类似。
Startup
类是当应用程序的host
被构建时指定的。通常情况下,Startup
类通过 host
构造器(builder)的 WebHostBuilderExtensions.UseStartup<TStartup>
方法来指定:
1 | public class Program |
主机(host) 通过 Startup
类的 构造器(constructor) 为 Startup
类提供其所依赖的服务。应用程序通过 Startup
类的 ConfigureServices
方法注册应用程序依赖的其它服务。 主机 提供的 服务 和应用程序提供的 服务 在 Startup
类的 Confugure
方法和应用程序的全局都可用。
当使用 通用主机(Generic Host [IHostBuilder]) 时,只有下面的服务可以被注入到 Startup
类的 构造器 :
- IWebHostEnvironment
- IHostEnvironment
- IConfiguration
1 | public class Startup |
多数 服务 在 Startup
类的 Confugure
方法被调用前是不可用的。
多重启动
当应用程序为不同的环境定义不同的 启动类 (例如: StartupDevelopment
),对应该环境的 启动类 会在运行时被选择。类名的后缀匹配当前运行环境的 启动类 被优先应用。比如,如果应用程序运行在开发环境下,并且定义了 StartupDevelopment
和 Startup
两个类,那么 StartupDevelopment
将会被运行时应用。
Startup
类的 ConfigureServices
方法
ConfigureServices
方法是可选的。
它由 主机 在 Configure
方法被调用之前调用,用来配置应用程序所依赖的 服务 ,主机 可能在 Startup
类的构造函数被调用前配置一些 Startup
类要用到的服务。
对于那些经常用到的 服务,IServiceCollection
定义了一些形似 Add{Service}
的扩展方法,例如:AddDbContext
、 AddDefaultIdentity
、 AddEntityFrameworkStores
、 AddRazorPages
:
1 | public class Startup |
将 服务 添加到 服务容器 使得这些服务在 Startup
类的 Configure
方法中可用,并且在应用程序的全局可用,这些服务可以通过 依赖注入 机制或从 ApplicationServices
中取得。
Startup
类的 Configure
方法
Configure
方法用于配置应用程序如何响应HTTP请求,它通过将 中间件(middleware) 组件添加到 IApplicationBuilder
实例来配置处理HTTP请求的 流水线(pipeline) ,IApplicationBuilder
对Configure
方法可用,但是它并没有被注册到 服务容器 , 宿主 创建IApplicationBuilder
实例并将它做为参数直接传递给Configure
方法。
ASP.NET Core应用程序模板配置了支持如下功能的HTTP处理 流水线 :
- 开发者异常页面(Developer Exception Page)
- 异常处理(Exception handler)
- HTTP Strict Transport Security (HSTS)
- HTTPS重定向(HTTPS redirection)
- 静态文件(Static files)
- ASP.NET Core MVC and Razor Pages
1 | public class Startup |
上面的代码针对的是 Razor Pages 编程框架,使用 MVC 框架的代码和这段代码类似。
每一个 Use{XXX}
扩展方法添加一个 中间件 到HTTP请求处理 管道线 ,例如:UseStaticFiles
配置了用于处理静态文件的中间件。
流水线 中的每个中间件处理完自己的任务后负责调用流水线中的下一个中间件,或者如果满足某个特定条件的话 短路 流水线的处理流程,结束HTTP处理。
其它的服务,比如IWebHostEnvironment
、ILoggerFactory
或者其它任何定义在ConfigureServices
方法中的中间件,都能通过Configure
方法的参数签名来指定。然后这些参数中指定服务如果可用的话就会被依赖注入机制注入。
不通过Startup
类来配置服务
如果不想通过Startup
类来配置应用程序依赖的服务及HTTP处理流水线,那么可以通过调用宿主建造器(builder)的ConfigureServices
方法和Configure
方法来实现同样的功能。对ConfigureServices
的多次调用会依次将服务加入到服务容器,如果对Configure
多次调用,那么最后一次的调用生效。
1 | public class Program |
通过 启动筛选器(startup filters) 扩展Startup
类
使用IStartupFilter
:
这个主题不太容易理解,请参见这篇对IStartupFilter
进行详细研究的文章。
可在应用程序通过
Startup.Configure
配置的中间件流水线之前或之后配置其它的中间件,而不用显式调用Use{Middleware}
。ASP.NET Core使用IStartupFilter
在http处理流水线的开头添加默认处理中间件,而不必要求应用程序的作者显式地注册默认的中间件。通过IStartupFilter
,不同的组件可以以应用程序作者的名义调用Use{Middleware}
。创建一个
Configure
方法调用的流水线。IStartupFilter.Configure
可以设置一个中间件在某个库添加的http处理中间件这前或之后运行。
IStartupFilter
实现了一个Configure
方法,此方法接收并返回一个Action<IApplicationBuilder>
。IApplicationBuilder
定义了一个用于配置应用程序http请求处理流水线的类。
每个IStartupFilter
可以添加一个或多个中间件到http请求处理流水线,筛选器按照它们被添加到服务容器中的顺序被调用。
下面这个例子演示了如何通过IStartupFilter
注册一个中间件,例子中的RequestSetOptionsMiddleware
中间件从http请求的查询字符串参数中取得需要的值,并将这个值赋给httpContext.Items["option"]
。
1 | public class RequestSetOptionsMiddleware |
RequestSetOptionsMiddleware
在RequestSetOptionsStartupFilter
类中进行配置:
1 | public class RequestSetOptionsStartupFilter : IStartupFilter |
IStartupFilter
通过IHostBuilder.ConfigureServices
注册在服务容器中:
1 | public class Program |
当http请求的查询字符串中包含option
参数的值时,RequestSetOptionsMiddleware
会在ASP.NET Core中间件渲染 响应(response) 之前处理httpContext.Items["option"]
的赋值操作。
中间件按照IStartupFilter
注册的顺序执行:
多个
IStartupFilter
实现可能操作相同的对象,如果中间件的执行顺序与执行结果相关,那么就要根据需要排列IStartupFilter
的执行顺序以达到需要的执行结果。库可能通过一个或多个
IStartupFilter
实现来添加中间件,这些中间件在应用程序通过IStartupFilter
注册的中间件之前或之后运行,要在库添加的中间件之前执行某个IStartupFilter
中间件:- 在把库添加到服务容器之前注册你想要执行的服务。
- 要在库添加的中间件之后执行某个
IStartupFilter
中间件,在把库添加到服务容器之后,再注册你想要执行的服务。