ASP.NET Core的启动和运行机制是如何一步步构建并高效执行的?

摘要:[TOC] ASP .NET Core 的运行机制 1. Web Server : ASP.NET Core 提供两种服务器可用, 分别是 Kestrel 和 HTTP.sys (Core 1.x 中被命名为 WebListener), K
目录ASP .NET Core 的运行机制ASP .NET Core 的启动ASP .NET Core 的管道和中间件参考 ASP .NET Core 的运行机制 Web Server: ASP.NET Core 提供两种服务器可用, 分别是 Kestrel 和 HTTP.sys (Core 1.x 中被命名为 WebListener), Kestrel是一个跨平台的Web服务器。 HTTP.sys只能用在Windows系统中. Internet: 当需要部署在Internal Network 中并需要 Kestrel 中没有的功能(如 Windows 身份验证)时,可以选择HTTP.sys。 IIS、Apache、Nginx: Kestrel 可以单独使用 ,也可以将其与反向代理服务器(如 IIS、Nginx 或 Apache)结合使用。 请求经这些服务器进行初步处理后转发给Kestrel(即图中虚线的可选流程). ASP .NET Core 的启动 public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .Build(); } Main: 程序的起点. ASP .NET Core 应用程序本质上是控制台应用程序。 CreateDefaultBuilder:创建并配置WebHostBuilder, 首先调用Create­DefaultBuilder( 如图所示, 它是一系列配置的大综合,下文做详细介绍), 进行一系列配置。 UseStartup: 指定Startup为启动配置文件. 在Startup中, 将进行两个比较重要的工作, 服务的依赖注入和配置管道。 ConfigureServices方法是注册服务 Configure方法是配置管道,用来具体指定如何处理每个http请求的, 例如我们可以让这个程序知道我使用mvc来处理http请求, 那就调用app.UseMvc()这个方法就行. BuildWebHost:生成WebHostBuilder并进行了一系列配置之后, 通过这个WebHostBuilder来Build出一个IWebHost。 Run:调用IWebHost的Run方法使之开始运行。 Create­DefaultBuilder public static IWebHostBuilder CreateDefaultBuilder(string[] args) { var builder = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .ConfigureAppConfiguration((hostingContext, config) => { var env = hostingContext.HostingEnvironment; config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true); if (env.IsDevelopment()) { var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName)); if (appAssembly != null) { config.AddUserSecrets(appAssembly, optional: true); } } config.AddEnvironmentVariables(); if (args != null) { config.AddCommandLine(args); } }) .ConfigureLogging((hostingContext, logging) => { logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); logging.AddConsole(); logging.AddDebug(); }) .UseIISIntegration() .UseDefaultServiceProvider((context, options) => { options.ValidateScopes = context.HostingEnvironment.IsDevelopment(); }); return builder; } UseKestrel 指定服务器使用 Kestrel,若使用HttpSys,需使用UseHttpSys。 UseContentRoot 指定根目录 ConfigureAppConfiguration 读取配置文件 ConfigureLogging 配置日志处理程序 UseIISIntegration 将应用程序配置为在 IIS 中运行。如果应用程序没有使用 IIS 作为反向代理,那么 UseIISIntegration 不会有任何效果。因此,即使应用程序在非 IIS 方案中运行,也可以安全调用这种方法。 UseDefaultServiceProvider 设置默认的依赖注入容器。 ASP .NET Core 的管道和中间件 请求管道: 那些处理http requests并返回responses的代码组成了request pipeline(请求管道). 中间件: 我们可以使用一些程序来配置请求管道(request pipeline)以便处理requests和responses. 比如处理验证(authentication)的程序, MVC本身就是个中间件(middleware). 当接收到一个请求时,请求会交给中间件构成的中间件管道进行处理,管道就是多个中间件构成,请求从一个中间件的一端进入,从中间件的另一端出来,每个中间件都可以对HttpContext请求开始和结束进行处理. 自己写一个中间件测试下: 通过约定方法实现: public class Floor1Middleware { private readonly RequestDelegate _next; public Floor1Middleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { Console.WriteLine("Floor1Middleware In"); //Do Something //To FloorTwoMiddleware await _next(context); //Do Something Console.WriteLine("Floor1Middleware Out"); } } 添加扩展方法: public static class Floor1MiddlewareExtensions { public static IApplicationBuilder UseFloor1Middleware(this IApplicationBuilder builder) { return builder.UseMiddleware<Floor1Middleware>(); } } 通过 IMiddleware 实现 public class Floor3Middleware : IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { Console.WriteLine("Floor3Middleware In"); //Do Something //To FloorTwoMiddleware await next(context); //Do Something Console.WriteLine("Floor3Middleware Out"); } } public static class MiddlewareExtensions { public static IApplicationBuilder UseFloor3Middleware( this IApplicationBuilder builder) { return builder.UseMiddleware<Floor3Middleware>(); } } public void ConfigureServices(IServiceCollection services) { services.AddTransient<Floor3Middleware>(); services.AddMvc(); } 也可以用简要的写法,直接在Startup的Configure方法中这样写: app.Use(async (context, next) => { Console.WriteLine("Floor2Middleware In"); await next.Invoke(); Console.WriteLine("Floor2Middleware Out"); }); 测试中间件: public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseFloor1Middleware(); app.Use(async (context, next) => { Console.WriteLine("Floor2Middleware In"); await next.Invoke(); Console.WriteLine("Floor2Middleware Out"); }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseCookiePolicy(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } 运行查看输出为: DIDemo> Floor1Middleware In DIDemo> Floor2Middleware In DIDemo> Floor3Middleware In DIDemo> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] DIDemo> Route matched with {action = "Index", controller = "Home"}. Executing action DIDemo.Controllers.HomeController.Index (DIDemo) DIDemo> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] DIDemo> Executing action method DIDemo.Controllers.HomeController.Index (DIDemo) - Validation state: Valid DIDemo> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] DIDemo> Executed action method DIDemo.Controllers.HomeController.Index (DIDemo), returned result Microsoft.AspNetCore.Mvc.ViewResult in 0.1167ms. DIDemo> info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[1] DIDemo> Executing ViewResult, running view Index. DIDemo> info: Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4] DIDemo> Executed ViewResult - view Index executed in 3.3508ms. DIDemo> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2] DIDemo> Executed action DIDemo.Controllers.HomeController.Index (DIDemo) in 9.5638ms DIDemo> Floor3Middleware Out DIDemo> Floor2Middleware Out DIDemo> Floor1Middleware Out 参考 ASP.NET Core Middleware ASP .NET Core 一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系