本文不是針對初學者的入門文章,而是從asp.net core 5.0 源碼的角度分析程序是如何加載并運行的。
創(chuàng)建 ASP.NET Core Web App(MVC) 模板項目
運行 VS2019 并創(chuàng)建新的ASP.NET Core Web App(Model-View-Controller) 模板項目, 在創(chuàng)建向?qū)е?Target Framework選擇 .Net 5.0,我們暫時不需要任何的身份驗證 所以 Authentication Type
選擇 None,項目創(chuàng)建完成后目錄結構類似于:

直接 F5 運行,瀏覽器會默認打開 http://localhost:5000/ 的地址,模板只含有兩個頁面 Home 及 Privacy
分析模板代碼
下面來分析主程序,打開Program.cs
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
CreateHostBuilder 方法會創(chuàng)建并配置一個 builder 對象,然后調(diào)用Build方法創(chuàng)建一個IHost的實例,最后調(diào)用Run 方法啟動host。
下面一步步分析這段代碼。
首先Host是一個靜態(tài)類,命名空間是Microsoft.Extensions.Hosting, 這個靜態(tài)類中只包含兩個靜態(tài)方法,還是重載方法, 只參數(shù)不同
public static IHostBuilder CreateDefaultBuilder();
public static IHostBuilder CreateDefaultBuilder(string[] args);
來看看CreateDefaultBuilder具體的實現(xiàn),去掉了一些具體的配置代碼
public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new HostBuilder();
builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
//加載DOTNET_ 環(huán)境變量和命令行參數(shù)
});
builder.ConfigureAppConfiguration((hostingContext, config) =>
{
//添加json配置文件, user secret,環(huán)境變量和命令行參數(shù)
})
.ConfigureLogging((hostingContext, logging) =>
{
//添加log:Event log,Console log,Debug, Event source,配置文件的log
})
.UseDefaultServiceProvider((context, options) =>
{
//配置依賴注入服務的驗證信息
});
return builder;
}
通過調(diào)用此方法就初始化好了一個IHostBuilder的實例(HostBuilder)
,至此所有配置的加載以及代碼都是針對通用宿主(generic host),沒有針對asp.net core 或 HTTP 請求的任何代碼,在這個通用宿主的基礎上我們可以設置成控制臺程序,worker service,以及asp.net core 應用。
要把程序設成asp.net core, 程序調(diào)用IHostBuilder的一個擴展方法ConfigureWebHostDefaults,這個方法位于靜態(tài)類GenericHostBuilderExtensions 中, 調(diào)用此方法是為hosting web app加載一些默認的選項。
public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
{
if (configure is null)
{
throw new ArgumentNullException(nameof(configure));
}
return builder.ConfigureWebHost(webHostBuilder =>
{
WebHost.ConfigureWebDefaults(webHostBuilder);
configure(webHostBuilder);
});
}
此方法中繼續(xù)調(diào)用IHostBuilder的另外一個擴展方法ConfigureWebHost
public static IHostBuilder ConfigureWebHost(this IHostBuilder builder, Action<IWebHostBuilder> configure, Action<WebHostBuilderOptions> configureWebHostBuilder)
{
//省略一些參數(shù)的檢查代碼
// Light up custom implementations namely ConfigureHostBuilder which throws.
if (builder is ISupportsConfigureWebHost supportsConfigureWebHost)
{
return supportsConfigureWebHost.ConfigureWebHost(configure, configureWebHostBuilder);
}
var webHostBuilderOptions = new WebHostBuilderOptions();
configureWebHostBuilder(webHostBuilderOptions);
var webhostBuilder = new GenericWebHostBuilder(builder, webHostBuilderOptions);
configure(webhostBuilder);
builder.ConfigureServices((context, services) => services.AddHostedService<GenericWebHostService>());
return builder;
}
在ConfigureWebHost中,首先創(chuàng)建一個GenericWebHostBuilder
的對象,然后調(diào)用的傳入的委托方法,在上一個ConfigureWebHostDefaults方法中,傳入的委托方法是
webHostBuilder =>
{
WebHost.ConfigureWebDefaults(webHostBuilder);
configure(webHostBuilder);
}
委托方法先是調(diào)用的靜態(tài)類WebHost
)
中的ConfigureWebDefaults,然后接著調(diào)用上一級傳入的委托方法及Program.cs中傳入的
webBuilder =>
{
webBuilder.UseStartup<Startup>();
}
ConfigureWebHostDefaults
下面概括一下這個擴展方法
- 添加 ASPNETCORE_ 開頭的環(huán)境變量
- 注冊 GenericHostService(詳見ConfigureWebHost方法), 這個類是IHostService的一個實現(xiàn),這個類實現(xiàn)了讓asp.net core 可以使用 generic host
- 配置 Kestrel 當作默認Http Server 服務,反向代理伺服器(例如IIS,Nginx,Apache)會把接受http請求,并轉(zhuǎn)發(fā)給Kestrel
- 注冊服務HostFilteringStartupFilter
- 在Windows上啟動IIS 集成
- 注冊路由服務
HostBuilder
這是一個非常重要的類,前面我們講到了CreateDefaultBuilder是用來初始化一個IHostBuilder的實例,這個實例的默認實現(xiàn)就是HostBuilder,前面講到的所有配置信息都是應用到這個類的實例的,這個類里定義了幾個委托的list集合
private List<Action<IConfigurationBuilder>> _configureHostConfigActions = new List<Action<IConfigurationBuilder>>();
private List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppConfigActions = new List<Action<HostBuilderContext, IConfigurationBuilder>>();
private List<Action<HostBuilderContext, IServiceCollection>> _configureServicesActions = new List<Action<HostBuilderContext, IServiceCollection>>();
private List<IConfigureContainerAdapter> _configureContainerActions = new List<IConfigureContainerAdapter>();
前面我們看到的幾乎所有的加載設置,服務之類的都是添加到對應的委托集合中,然后這些委托會在后續(xù)的Build方法中被循環(huán)調(diào)用。
總結
我們今天創(chuàng)建了一個asp.net core 5.0 mvc模板項目,并解釋了CreateHostBuilder做的幾件事情
- 創(chuàng)建一個IHostBuilder的實例并加載一些針對generic host的設置,環(huán)境變量的添加、json配置文件加載、log等
- 接著調(diào)用ConfigureWebHostDefaults并宿主配置成能asp.net core的程序
接下來的一篇文章我會解釋一下Build這個方法。