ASP.NET Core - 从Program和Startup开始
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方法用来指定应用程序的启动类,这里主要有两个作用:
- 配置应用需要的服务(服务注册,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"]; ...
});
}
这里需要注意的是,Startup只是一个概念,类的名字是可以任意的,只需要在启动项UseStartup中指定你这个启动类即可。
总结
正如ASP.NET Core - 开篇所说的,一个ASP.NET Core应用其实就是一个控制台应用程序,它在应用启动时构建一个 Web 服务器,并且通过指定的Startup类来构建应用服务和请求管道,进而监听和处理所有的Http请求。
ASP.NET Core - 从Program和Startup开始的更多相关文章
- 如何在 asp.net core 3.x 的 startup.cs 文件中获取注入的服务
一.前言 从 18 年开始接触 .NET Core 开始,在私底下.工作中也开始慢慢从传统的 mvc 前后端一把梭,开始转向 web api + vue,之前自己有个半成品的 asp.net core ...
- asp.net core 系列 2 启动Startup类介绍
一.Startup类 ASP.NET Core 应用是一个控制台应用,它在其 Program.Main 方法中创建 Web 服务器.其中Main方法是应用的托管入口点,Main 方法调用 WebHos ...
- asp.netcore 3.1 program、Startup 类详解
Program类 public class Program { /// <summary> /// 应用程序入口 /// 1.asp.netcore 本质上是控制台程序 /// </ ...
- ASP.NET Core Web API中Startup的使用技巧
Startup类和服务配置 STARTUP CLASS AND THE SERVICE CONFIGURATION 在 Startup 类中,有两个方法:ConfigureServices 是用于 ...
- ASP.NET Core[源码分析篇] - Startup
应用启动的重要类 - Startup 在ASP.NET Core - 从Program和Startup开始这篇文章里面,我们知道了Startup这个类的重要性,它主要负责了: 配置应用需要的服务(服务 ...
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...
- ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行
ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...
- ASP.NET Core 运行原理剖析
1. ASP.NET Core 运行原理剖析 1.1. 概述 1.2. 文件配置 1.2.1. Starup文件配置 Configure ConfigureServices 1.2.2. appset ...
- ASP.NET Core 实战:构建带有版本控制的 API 接口
一.前言 在上一篇的文章中,主要是搭建了我们的开发环境,同时创建了我们的项目模板框架.在整个前后端分离的项目中,后端的 API 接口至关重要,它是前端与后端之间进行沟通的媒介,如何构建一个 “好用” ...
随机推荐
- maven国内镜像(国内oschina的maven服务器关了)
Maven是官方的库在国外,连下载速度很慢.国内oschina的maven服务器很早之前就关了.今天发现阿里云的一个中央仓库,亲测可用. 找到E:\maven\apache-maven-3.5.2\c ...
- Django中Middleware中间件
Django中Middleware中间件 1 Middleware中间件概述 django中间middleware实质就是一个类,django会根据自己的规则在合适的时机执行中间件相应的方法.实际上当 ...
- Dropwizard入门及开发步骤
Dropwizard介绍 Dropwizard结构的服务组成 开发步骤 Dropwizard介绍 Dropwizard是一个微服务框架, 是各项技术的一个集成封装.它包含了以下组件: 嵌入式Jetty ...
- 如何使用FluentMigrator进行数据库迁移
标题:如何使用FluentMigrator进行数据库迁移 地址:https://www.cnblogs.com/lwqlun/p/10649949.html 作者: Lamond Lu FluentM ...
- Git操作GitHub时的Proxy配置
无论是使用Android Studio中,VCS >> Git >> Clone, 还是直接Git Clone命令,clone GitHub项目时,出现错误提示:LibreSS ...
- 陪你解读Spring Batch(二)带你入手Spring Batch
前言 说得多不如show code.上一章简单介绍了一下Spring Batch.本章将从头到尾搭建一套基于Spring Batch(2.1.9).Spring(3.0.5).mybatis(3.4. ...
- 内部类、异常以及 LeetCode 每日一题
1 内部类 内部类的作用: 内部类提供了更好的封装,可以把内部类隐藏于外部类之内,不允许同一个包中的其他类访问该类.(例如给“牛”这个类组合一个“牛腿”,则可以把牛腿定义成内部类,因为牛腿脱离了牛没有 ...
- (一)初识Redis
1.redis简介 Redis是一个速度非常快的key-value非关系型存储数据库,可以存储5种形态的键值对,可以将存储在内存中的键值对持久化到硬盘,可以使用复制特性扩展读性能,还可以使用客户端分片 ...
- Linux 初始环境配置 以及避坑 (详细)
没事儿喜欢自己装个虚拟机捣鼓捣鼓,经过几次装一些Linux 经验, 有时候 电脑了 .想重新系统了,又要重新去配置环境, 有时候又要去查很多很多命令 . 记录分享下Linux 下配置开发环境以及桌面 ...
- 第一周Python学习笔记
Python 基本语法: ① Python程序的格式:1.用代码高亮来标识函数丶语句等等 本身的代码高亮并没有实际的意义,只是用来辅助编程人员和阅读人员 更好的识别 2.程序以缩进来标识语句,缩进用 ...