ASP.NET Core 5.0 (1) - 模板項目創(chuàng)建及解析

本文不是針對初學者的入門文章,而是從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)建完成后目錄結構類似于:

MVCTemplate.jpg

直接 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這個方法。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容