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 != )
return;
string str = hostingContext.Configuration["AllowedHosts"];
string[] strArray1;
if (str == null)
strArray1 = (string[]) null;
else
strArray1 = str.Split(new char[]{ ';' }, StringSplitOptions.RemoveEmptyEntries);
string[] strArray2 = strArray1;
HostFilteringOptions filteringOptions = options;
string[] strArray3;
if (strArray2 == null || strArray2.Length == )
strArray3 = new string[]{ "*" };
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方法用来指定应用程序的启动类,这里主要有两个作用:

  1. 配置应用需要的服务(服务注册,ConfigureServices方法)。
  2. 创建应用的请求处理处理管道(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的扩展。

  需要注意的有三个地方:

  1. 应尽早在管道中调用异常处理委托,这样就能捕获在后续管道发生的异常,所以能看到微软的经典写法是先把异常处理的中间件写在最前面,这样方可捕获稍后调用中发生的任何异常。
  2. 当某个中间件不将请求传递给下一个中间件时,这被称为“请求管道短路”。 我们通常都会需要短路,这样可以避免资源浪费,类似与当抛出异常时我们将不会再往下请求,因为这完全没有必要:)
  3. 如果你想某些模块不需要授权就能访问,应把这些模块放在认证模块前面,所以我们一般会把访问静态文件的中间件放在认证模块的前面。
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"]; ...
});
}

   这里需要注意的是,Startup只是一个概念,类的名字是可以任意的,只需要在启动项UseStartup中指定你这个启动类即可。

  总结

  正如ASP.NET Core - 开篇所说的,一个ASP.NET Core应用其实就是一个控制台应用程序,它在应用启动时构建一个 Web 服务器,并且通过指定的Startup类来构建应用服务和请求管道,进而监听和处理所有的Http请求。

ASP.NET Core - 从Program和Startup开始的更多相关文章

  1. 如何在 asp.net core 3.x 的 startup.cs 文件中获取注入的服务

    一.前言 从 18 年开始接触 .NET Core 开始,在私底下.工作中也开始慢慢从传统的 mvc 前后端一把梭,开始转向 web api + vue,之前自己有个半成品的 asp.net core ...

  2. asp.net core 系列 2 启动Startup类介绍

    一.Startup类 ASP.NET Core 应用是一个控制台应用,它在其 Program.Main 方法中创建 Web 服务器.其中Main方法是应用的托管入口点,Main 方法调用 WebHos ...

  3. asp.netcore 3.1 program、Startup 类详解

    Program类 public class Program { /// <summary> /// 应用程序入口 /// 1.asp.netcore 本质上是控制台程序 /// </ ...

  4. ASP.NET Core Web API中Startup的使用技巧

    Startup类和服务配置   STARTUP CLASS AND THE SERVICE CONFIGURATION 在 Startup 类中,有两个方法:ConfigureServices 是用于 ...

  5. ASP.NET Core[源码分析篇] - Startup

    应用启动的重要类 - Startup 在ASP.NET Core - 从Program和Startup开始这篇文章里面,我们知道了Startup这个类的重要性,它主要负责了: 配置应用需要的服务(服务 ...

  6. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  7. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  8. ASP.NET Core 运行原理剖析

    1. ASP.NET Core 运行原理剖析 1.1. 概述 1.2. 文件配置 1.2.1. Starup文件配置 Configure ConfigureServices 1.2.2. appset ...

  9. ASP.NET Core 实战:构建带有版本控制的 API 接口

    一.前言 在上一篇的文章中,主要是搭建了我们的开发环境,同时创建了我们的项目模板框架.在整个前后端分离的项目中,后端的 API 接口至关重要,它是前端与后端之间进行沟通的媒介,如何构建一个 “好用” ...

随机推荐

  1. objectid.go源码阅读

    )) } // func), ), ), ), ])<<])<<)]) } //获取])<<])<<])<<]), //转化为十进制的int ...

  2. HTTP 和 WebSocket的区别

    有关http和WebSocket 的区别网上有很多的质料. 个人在此仅仅是记录以下自己的学习心得,自己的理解. 1. http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要 ...

  3. Opencv(C++)实现邻近插值算法

    #include <opencv2/opencv.hpp> using namespace std; using namespace cv; void Zero_order(const M ...

  4. 遍历数组 foreach

    package com.java.array; public class Myforeach { public static void main(String[] ARGS){ /* int arr[ ...

  5. C++实现离散数学的关系类,支持传递闭包运算

    #include <vector> #include <cassert> #include <iostream> using namespace std; clas ...

  6. Python-常用 Linux 命令的基本使用

    常用 Linux 命令的基本使用 操作系统 作用:管理好硬件设备,让软件可以和硬件发生交互类型 桌面操作系统 Windows macos linux 服务器操作系统 linux Windows ser ...

  7. MIP ACCESS细节剖析

    什么是 MIP ACCESS MIP ACCESS 由百度 MIP 团队开发的一种页面访问权限控制机制,能够允许网页发布者在页面元素中定义内容标记,并结合用户访问情况进行综合评价,从而展现或隐藏页面中 ...

  8. com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server 报错问题

    com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known serve ...

  9. Zabbix-server 3.4 安装详细和修改web界面中文出现的乱码(一)

    1. 老套路先来个Zabbix简介: Zabbix是一个企业级的.开源的.分布式的监控套件: Zabbix可以监控网络和服务的监控状况. Zabbix利用灵活的告警机制,允许用户对事件发送Email. ...

  10. Android 网络优化,使用 HTTPDNS 优化 DNS,从原理到 OkHttp 集成

    一.前言 谈到优化,首先第一步,肯定是把一个大功能,拆分成一个个细小的环节,再单个拎出来找到可以优化的点,App 的网络优化也是如此. 在 App 访问网络的时候,DNS 解析是网络请求的第一步,默认 ...