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 - 开篇 <https://www.cnblogs.com/lex-wu/p/10604810.html>
所说的重要对象: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 - 开篇 <https://www.cnblogs.com/lex-wu/p/10604810.html>
所说的,一个ASP.NET Core应用其实就是一个控制台应用程序,它在应用启动时构建一个 Web
服务器,并且通过指定的Startup类来构建应用服务和请求管道,进而监听和处理所有的Http请求。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信