一、背景介绍
本文以ASP.NET Core 2.1.2版本API程序来说明。
在我们新建ASP.NET Core项目时,项目根目录下会自动建立Program.cs和Startup.cs两个类文件。
Program.cs 作为 Web 应用程序的默认入口,不做任何修改的情况下,会调用同目录下 Startup.cs 中的 ConfigureServices 方法 和 Configure 方法。
应用启动的流程如下图所示:
本文主要介绍Startup.cs 类,认识其功能和作用,深入了解其内部运行机制,以便于更好地在项目中进行应用。
二、Program类介绍
Program.Main方法是应用程序的托管入口。
在构建应用程序的主机(WebHost)时,在主程序的Web Host生成器(IWebHostBuilder)的 UseStartup <TStartup>
扩展方法中指定启动类名称。ASP.NET Core应用程序的启动类,按照惯例命名为Startup
。而Main入口通过主机生成器(IWebHostBuilder)调用Build时,生成对应的应用程序的主机(WebHost),并启动运行(Run)。
1 public static void Main(string[] args) 2 { 3 CreateWebHostBuilder(args).Build().Run(); 4 } 5 6 public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 7 WebHost.CreateDefaultBuilder(args) 8 .UseUrls("http://*:5002") 9 .UseStartup<Startup>();
三、Startup类介绍
Startup类用于配置服务和应用程序的请求管道。
当应用程序启动时,运行时会调用Startup类的 ConfigureServices 和 Configure方法。
1 public class Startup 2 { 3 public static ILoggerRepository Repository { get; set; } 4 public Startup(IConfiguration configuration) 5 { 6 Configuration = configuration; 7 // 日志配置 8 Repository = LogManager.CreateRepository("NETCoreRepository"); 9 XmlConfigurator.Configure(Repository, new FileInfo("log4net.config")); 10 } 11 12 public IConfiguration Configuration { get; } 13 14 // This method gets called by the runtime. Use this method to add services to the container. 15 public void ConfigureServices(IServiceCollection services) 16 { 17 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 18 // 跨域,允许所有域名访问 19 services.AddCors(options => options.AddPolicy("AllowCorsDomain", p => p.WithOrigins("*") 20 .AllowAnyMethod() 21 .AllowAnyHeader() 22 .AllowCredentials())); 23 } 24 25 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 26 public void Configure(IApplicationBuilder app, IHostingEnvironment env) 27 { 28 DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions(); 29 defaultFilesOptions.DefaultFileNames.Clear(); 30 defaultFilesOptions.DefaultFileNames.Add("index.html"); 31 app.UseDefaultFiles(defaultFilesOptions); 32 app.UseStaticFiles(); 33 34 if (env.IsDevelopment()) 35 { 36 app.UseDeveloperExceptionPage(); 37 } 38 39 app.UseMvc(); 40 app.UseCors("AllowCorsDomain"); 41 } 42 }
其中,Startup类必须定义Configure方法,但是可选择定义一个ConfigureServices 方法,这些方法将在应用程序启动时被调用。
1、ConfigureServices方法:用于设置应用程序所需要的服务。
ConfigureServices 方法在Configure方法配置应用程序服务之前被主机(WebHost)调用。其中按常规设置配置选项(appsettings.json)。
对于需要大量设置的功能,IServiceCollection 上有 Add{Service} 扩展方法,将服务添加到服务容器,使其在应用程序和Configure方法中可用。服务通过依赖关系注入(DI)或 ApplicationServices 进行解析。例如:
1 // 添加MVC设置兼容版本服务. 2 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 3 4 // 添加应用程序服务. 5 services.AddTransient<IEmailSender, AuthMessageSender>();
2、Configure方法:用于指定应用程序响应HTTP请求的方式。
可通过将中间件(middleware)组件添加到IApplicationBuilder实例来配置请求管道。Configure方法可使用 IApplicationBuilder,但未在服务容器中注册。托管创建 IApplicationBuilder并将其直接传递到Configure。
请求管道中的每个中间件组件负责调用管道中的下一个组件,或在适当情况下使链发生短路。 如果中间件链中未发生短路,则每个中间件都有第二次机会在将请求发送到客户端前处理该请求。该方法接受IApplicationBuilder作为参数,同时还可以接收其他一些可选参数,如IHostingEnvironment和ILoggerFactory。一般而言,只要将服务注册到configureServices方法中时,都可以在该方法中使用。
3、扩展Startup方法:IStartupFilter
使用IStartupFilter来对Startup功能进行扩展,在应用的Configure中间件管道的开头或末尾使用IStartupFilter来配置中间件。IStartupFilter有助于确保当库在应用请求处理管道的开端或末尾添加中间件的前后运行中间件。
IStartupFilter
接口存在于Microsoft.AspNetCore.Hosting.Abstractions程序集中,它仅定义了一个接口方法。
1 namespace Microsoft.AspNetCore.Hosting 2 { 3 public interface IStartupFilter 4 { 5 Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next); 6 } 7 }
其中Configure
方法返回了一个变量Action
。
当创建一个ASP.NET Core应用程序的时候,IApplicationBuilder
负责配置ASP.NET Core的中间件管道。例如:
1 public void Configure(IApplicationBuilder app) 2 { 3 app.UseStaticFiles(); 4 5 app.UseMvc(routes => 6 { 7 routes.MapRoute( 8 name: "default", 9 template: "{controller=Home}/{action=Index}/{id?}"); 10 }); 11 }
在这个方法中,可以直接使用IApplicationBuilder
参数,并且可以向其中添加各种中间件。
使用IStartupFilter
, 可以指定并返回一个Action
类型的泛型委托,这意味除了可以使用方法提供的泛型委托配置IApplicationBuilder
对象, 还需要返回一个泛型委托。
IStartupFilter
方法可以接受一个配置IApplicationBuilder
的方法,换而言之IStartupFilter.Configure
方法可以使用Startup.Configure
方法作为参数。例如:
1 Startup _startup = new Startup(); 2 Action<IApplicationBuilder> startupConfigure = _startup.Configure; 3 4 // 将startupConfigure 作为filter1.Configure(startupConfigure)的参数 5 IStartupFilter filter1 = new StartupFilter1(); 6 Action<IApplicationBuilder> filter1Configure = filter1.Configure(startupConfigure) 7 8 // 将filter1Configure作为filter2.Configure(filter1Configure)的参数 9 IStartupFilter filter2 = new StartupFilter2(); 10 Action<IApplicationBuilder> filter2Configure = filter2.Configure(filter1Configure)
关于IStartupFilter的例子:
1 public class AutoRequestServicesStartupFilter : IStartupFilter 2 { 3 public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) 4 { 5 return builder => 6 { 7 builder.UseMiddleware<RequestServicesContainerMiddleware>(); 8 next(builder); 9 }; 10 } 11 }
默认情况下,WebHostBuilder
在初始化时会注册一个IStartupFilter
- AutoRequestServicesStartupFilter。
本质上,它在中间件管道的开头添加了一个额外的中间件,即RequestServicesContainerMiddleware
。
这是唯一一个默认注册的IStartupFilter
,因此在这种情况下,参数next
将是Startup
类的Configure
方法。
注册IStartupFilter
1 private IServiceCollection BuildHostingServices() 2 { 3 ... 4 services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>(); 5 ... 6 }
参考资料:
- ASP.NET Core 菜鸟之路:从Startup.cs说起
- ASP.NET Core 应用程序Startup类介绍
- https://www.cnblogs.com/lwqlun/p/10279874.html#3437817747