Program
我们先看一下 1.x 和 2.x 的程序入口项的一个差异
- 1.x
- public class Program
- {
- public static void Main(string[] args)
- {
- var host = new webHostBuilder()
- .UseKestrel()
- .UseContentRoot(Directory.GetCurrentDirectory())
- .UseIISIntegration()
- .UseStartup<Startup>()
- .Build();
- host.Run();
- }
- }
- 2.x
- public class Program
- {
- public static void Main(string[] args)
- {
- BuildWebHost(args).Run();
- }
- public static IWebHost BuildWebHost(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseStartup<Startup>()
- .Build();
- }
2.x 对默认配置进行了简化, 把一些基本配置移动了 CreateDefaultBuilder 方法中
- public static IWebHostBuilder CreateDefaultBuilder(string[] args)
- {
- IWebHostBuilder hostBuilder = new WebHostBuilder()
- .UseKestrel((Action<WebHostBuilderContext, KestrelServerOptions>) ((builderContext, options) => options.Configure((IConfiguration) builderContext.Configuration.GetSection("Kestrel"))))
- .UseContentRoot(Directory.GetCurrentDirectory())
- .ConfigureAppConfiguration((Action<WebHostBuilderContext, IConfigurationBuilder>) ((hostingContext, config) =>
- {
- IHostingEnvironment hostingEnvironment = hostingContext.HostingEnvironment;
- config.AddJsonFile("appsettings.json", true, true)
- .AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true);
- if (hostingEnvironment.IsDevelopment())
- {
- Assembly assembly = Assembly.Load(new AssemblyName(hostingEnvironment.ApplicationName));
- if (assembly != (Assembly) null)
- config.AddUserSecrets(assembly, true);
- }
- config.AddEnvironmentVariables();
- if (args == null)
- return;
- config.AddCommandLine(args);
- }))
- .ConfigureLogging((Action<WebHostBuilderContext, ILoggingBuilder>) ((hostingContext, logging) =>
- {
- logging.AddConfiguration((IConfiguration) hostingContext.Configuration.GetSection("Logging"));
- logging.AddConsole();
- logging.AddDebug();
- }))
- .ConfigureServices((Action<WebHostBuilderContext, IServiceCollection>) ((hostingContext, services) =>
- {
- services.PostConfigure<HostFilteringOptions>((Action<HostFilteringOptions>) (options =>
- {
- if (options.AllowedHosts != null && options.AllowedHosts.Count != 0)
- return;
- string str = hostingContext.Configuration["AllowedHosts"];
- string[] strArray1;
- if (str == null)
- strArray1 = (string[]) null;
- else
- strArray1 = str.Split(new char[1]{ ';' }, StringSplitOptions.RemoveEmptyEntries);
- string[] strArray2 = strArray1;
- HostFilteringOptions filteringOptions = options;
- string[] strArray3;
- if (strArray2 == null || strArray2.Length == 0)
- strArray3 = new string[1]{ "*" };
- else
- strArray3 = strArray2;
- filteringOptions.AllowedHosts = (IList<string>) strArray3;
- }));
- services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>((IOptionsChangeTokenSource<HostFilteringOptions>) new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
- services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
- }))
- .UseIISIntegration()
- .UseDefaultServiceProvider((Action<WebHostBuilderContext, ServiceProviderOptions>) ((context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment()));
- if (args != null)
- hostBuilder.UseConfiguration((IConfiguration) new ConfigurationBuilder().AddCommandLine(args).Build());
- return hostBuilder;
- }
这里我们可以看到在 CreateDefaultBuilder 生成器中, 定义了默认使用的 Web 服务器 (UseKestrel, 使用的是 KestrelServer) 和一些基础的配置, 包括文件路径, 应用配置 (按 appsettings.JSON,appsettings.{Environment}.JSON 次序加载), 环境变量, 日志, IIS 集成等, 如果需要的话, 还可以指定其他类型的 Server(IIS HTTP Server,HTTP.sys Server) 和自定义 Server(继承 IServer).
返回到 Program 中, 在获取到了 WebHostBuilder 之后紧接着就指定了启动类 UseStartup<Startup>(),Build 方法是 WebHostBuilder 最终的目的, 将构造一个 WebHost 返回, 这里引出了我们在 ASP.NET Core - 开篇所说的重要对象: WebHost, 并且运行它的 Run 方法用于启动应用并开始监听所有到来的 HTTP 请求.
Startup
Startup 方法用来指定应用程序的启动类, 这里主要有两个作用:
配置应用需要的服务(服务注册, ConfigureServices 方法).
创建应用的请求处理处理管道(Configure 方法).
- public class Startup
- {
- private readonly IHostingEnvironment _env;
- private readonly IConfiguration _config;
- private readonly ILoggerFactory _loggerFactory;
- public Startup(IHostingEnvironment env, IConfiguration config,
- ILoggerFactory loggerFactory)
- {
- _env = env;
- _config = config;
- _loggerFactory = loggerFactory;
- }
- // 注入服务到容器中
- public void ConfigureServices(IServiceCollection services)
- {
- var logger = _loggerFactory.CreateLogger<Startup>();
- if (_env.IsDevelopment())
- {
- // Development service configuration
- logger.LogInformation("Development environment");
- }
- else
- {
- // Non-development service configuration
- logger.LogInformation($"Environment: {_env.EnvironmentName}");
- }
- ...
- }
- // 配置 Http 请求处理管道
- public void Configure(IApplicationBuilder App)
- {
- ...
- }
- }
Startup 类的 执行顺序: 构造 -> ConfigureServices -> Configure
1)Startup Constructor(构造函数)
上面的构造函数引出了我们开篇说的三个重要对象: IHostingEnvironment ,IConfiguration ,ILoggerFactory , 这里先讲构造函数的作用, 这些对象后面会分篇讲. 显而易见, 这里主要是通过依赖注入实例化了该类中需要用到的对象(根据自己的业务), 比较简单
2) ConfigureServices
首先这个方法是可选的, 它的参数是 IServiceCollection, 这也是我们开篇说的重要对象, 而且是非常重要的对象, 这是一个原生的 IoC 容器, 所有需要用到的服务都可以注册到里面, 一般是通过约定风格 services.Addxxx, 这样就可以让这些服务在应用和 Configure 方法使用(用来构建管道).
3)Configure
用于构建管道处理 Http 请求, 管道中的每个中间件 (Middleware) 组件负责请求处理和选择是否将请求传递到管道中的下一个组件, 在这里我们可以添加自己想要的中间件来处理每一个 Http 请求, 一般是使用上面的 ConfigureServices 方法中注册好的服务, 一般的用法是 App.Usexxx, 这个 Usexxx 方法是基于 IApplicationBuilder 的扩展.
需要注意的有三个地方:
应尽早在管道中调用异常处理委托, 这样就能捕获在后续管道发生的异常, 所以能看到微软的经典写法是先把异常处理的中间件写在最前面, 这样方可捕获稍后调用中发生的任何异常.
当某个中间件不将请求传递给下一个中间件时, 这被称为 "请求管道短路". 我们通常都会需要短路, 这样可以避免资源浪费, 类似与当抛出异常时我们将不会再往下请求, 因为这完全没有必要:)
如果你想某些模块不需要授权就能访问, 应把这些模块放在认证模块前面, 所以我们一般会把访问静态文件的中间件放在认证模块的前面.
- public void Configure(IApplicationBuilder App)
- {
- if (env.IsDevelopment())
- {// Use the Developer Exception Page to report App runtime errors.
- App.UseDeveloperExceptionPage();
- }
- else
- {// Enable the Exception Handler Middleware to catch exceptions
- // thrown in the following middlewares.
- App.UseExceptionHandler("/Error");
- }
- // Return static files and end the pipeline.
- App.UseStaticFiles();
- // Use Cookie Policy Middleware to conform to EU General Data
- // Protection Regulation (GDPR) regulations.
- App.UseCookiePolicy();
- // Authenticate before the user accesses secure resources.
- App.UseAuthentication();
- // If the App uses session state, call Session Middleware after Cookie
- // Policy Middleware and before MVC Middleware.
- App.UseSession();
- // Add MVC to the request pipeline.
- App.UseMvc();
- }
如果你不想使用 Startup 类的话, 可以使用以下方式配置自己的服务注册和管道构建, 虽然这种方式有点 odd :)
- public class Program
- {
- public static IHostingEnvironment HostingEnvironment { get; set; }
- public static IConfiguration Configuration { get; set; }
- public static void Main(string[] args)
- {
- CreateWebHostBuilder(args).Build().Run();
- }
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .ConfigureAppConfiguration((hostingContext, config) =>
- {
- })
- .ConfigureServices(services =>
- {
- ...
- })
- .Configure(App =>
- {
- var loggerFactory = App.ApplicationServices
- .GetRequiredService<ILoggerFactory>();
- var logger = loggerFactory.CreateLogger<Program>();
- var env = App.ApplicationServices.GetRequiredServices<IHostingEnvironment>();
- var config = App.ApplicationServices.GetRequiredServices<IConfiguration>();
- logger.LogInformation("Logged in Configure");
- if (env.IsDevelopment())
- {
- ...
- }
- else
- {
- ...
- }
- var configValue = config["subsection:suboption1"];
- ...
- });
- }
总结
正如 ASP.NET Core - 开篇所说的, 一个 ASP.NET Core 应用其实就是一个控制台应用程序, 它在应用启动时构建一个 Web 服务器, 并且通过指定的 Startup 类来构建应用服务和请求管道, 进而监听和处理所有的 Http 请求.
来源: https://www.cnblogs.com/lex-wu/p/10693437.html