欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET Core基础1:应用启动流程

程序员文章站 2022-06-26 19:49:09
先看下ASP.NET Core的启动代码,如下图:通过以上代码,我们可以初步得出以下结论:所有的ASP.NET Core程序本质上也是一个控制台程序,使用Program的Main方法作为程序的入口。控制台Main入口-->IWebHostBuilder-->IWebHost-->Run,发现本质上就... ......

先看下asp.net core的启动代码,如下图:


通过以上代码,我们可以初步得出以下结论:

  • 所有的asp.net core程序本质上也是一个控制台程序,使用program的main方法作为程序的入口。
  • 控制台main入口-->iwebhostbuilder-->iwebhost-->run,发现本质上就是启动一个作为宿主的host。
  • 下面结合源码代详细分析下。

    宿主构造器:iwebhostbuilder

    看下webhost的静态方法createdefaultbuilder的源码。

    /// <summary>
            /// initializes a new instance of the <see cref="webhostbuilder"/> class with pre-configured defaults.
            /// </summary>
            /// <remarks>
            ///   the following defaults are applied to the returned <see cref="webhostbuilder"/>:
            ///     use kestrel as the web server and configure it using the application's configuration providers,
            ///     set the <see cref="ihostingenvironment.contentrootpath"/> to the result of <see cref="directory.getcurrentdirectory()"/>,
            ///     load <see cref="iconfiguration"/> from 'appsettings.json' and 'appsettings.[<see cref="ihostingenvironment.environmentname"/>].json',
            ///     load <see cref="iconfiguration"/> from user secrets when <see cref="ihostingenvironment.environmentname"/> is 'development' using the entry assembly,
            ///     load <see cref="iconfiguration"/> from environment variables,
            ///     load <see cref="iconfiguration"/> from supplied command line args,
            ///     configure the <see cref="iloggerfactory"/> to log to the console and debug output,
            ///     and enable iis integration.
            /// </remarks>
            /// <param name="args">the command line args.</param>
            /// <returns>the initialized <see cref="iwebhostbuilder"/>.</returns>
            public static iwebhostbuilder createdefaultbuilder(string[] args)
            {
                var builder = new webhostbuilder();
    
                if (string.isnullorempty(builder.getsetting(webhostdefaults.contentrootkey)))
                {
                    builder.usecontentroot(directory.getcurrentdirectory());
                }
                if (args != null)
                {
                    builder.useconfiguration(new configurationbuilder().addcommandline(args).build());
                }
    
                builder.usekestrel((buildercontext, options) =>
                    {
                        options.configure(buildercontext.configuration.getsection("kestrel"));
                    })
                    .configureappconfiguration((hostingcontext, config) =>
                    {
                        var env = hostingcontext.hostingenvironment;
    
                        config.addjsonfile("appsettings.json", optional: true, reloadonchange: true)
                              .addjsonfile($"appsettings.{env.environmentname}.json", optional: true, reloadonchange: true);
    
                        if (env.isdevelopment())
                        {
                            var appassembly = assembly.load(new assemblyname(env.applicationname));
                            if (appassembly != null)
                            {
                                config.addusersecrets(appassembly, optional: true);
                            }
                        }
    
                        config.addenvironmentvariables();
    
                        if (args != null)
                        {
                            config.addcommandline(args);
                        }
                    })
                    .configurelogging((hostingcontext, logging) =>
                    {
                        logging.addconfiguration(hostingcontext.configuration.getsection("logging"));
                        logging.addconsole();
                        logging.adddebug();
                        logging.addeventsourcelogger();
                    })
                    .configureservices((hostingcontext, services) =>
                    {
                        // fallback
                        services.postconfigure<hostfilteringoptions>(options =>
                        {
                            if (options.allowedhosts == null || options.allowedhosts.count == 0)
                            {
                                // "allowedhosts": "localhost;127.0.0.1;[::1]"
                                var hosts = hostingcontext.configuration["allowedhosts"]?.split(new[] { ';' }, stringsplitoptions.removeemptyentries);
                                // fall back to "*" to disable.
                                options.allowedhosts = (hosts?.length > 0 ? hosts : new[] { "*" });
                            }
                        });
                        // change notification
                        services.addsingleton<ioptionschangetokensource<hostfilteringoptions>>(
                            new configurationchangetokensource<hostfilteringoptions>(hostingcontext.configuration));
    
                        services.addtransient<istartupfilter, hostfilteringstartupfilter>();
                    })
                    .useiis()
                    .useiisintegration()
                    .usedefaultserviceprovider((context, options) =>
                    {
                        options.validatescopes = context.hostingenvironment.isdevelopment();
                    });
    
                return builder;
            }

    1,usecontentroot

    指定web host使用的内容根目录,比如views。默认为当前应用程序根目录。


    2,useconfiguration

    //todo


    3,usekestrel

    使用kestrel作为默认的web server。


    4,configureappconfiguration

    设置当前应用程序配置。主要是读取 appsettings.json配置文件、开发环境中配置的usersecrets、添加环境变量和命令行参数 。


    5,configurelogging

    读取配置文件中的logging节点,配置日志系统。


    6,configureservices

    //todo


    7,useiis

    使用iis中间件。


    8,useiisintegration

    使用iisintegration中间件。


    9,usedefaultserviceprovider

    设置默认的依赖注入容器。

    宿主:iwebhost

    在asp.net core中定义了iwebhost用来表示web应用的宿主,并提供了一个默认实现webhost。宿主的创建是通过调用iwebhostbuilder的build()方法来完成的。看下源码:

    /// <summary>
            /// builds the required services and an <see cref="iwebhost"/> which hosts a web application.
            /// </summary>
            public iwebhost build()
            {
                if (_webhostbuilt)
                {
                    throw new invalidoperationexception(resources.webhostbuilder_singleinstance);
                }
                _webhostbuilt = true;
    
                var hostingservices = buildcommonservices(out var hostingstartuperrors);
                var applicationservices = hostingservices.clone();
                var hostingserviceprovider = getproviderfromfactory(hostingservices);
    
                if (!_options.suppressstatusmessages)
                {
                    // warn about deprecated environment variables
                    if (environment.getenvironmentvariable("hosting:environment") != null)
                    {
                        console.writeline("the environment variable 'hosting:environment' is obsolete and has been replaced with 'aspnetcore_environment'");
                    }
    
                    if (environment.getenvironmentvariable("aspnet_env") != null)
                    {
                        console.writeline("the environment variable 'aspnet_env' is obsolete and has been replaced with 'aspnetcore_environment'");
                    }
    
                    if (environment.getenvironmentvariable("aspnetcore_server.urls") != null)
                    {
                        console.writeline("the environment variable 'aspnetcore_server.urls' is obsolete and has been replaced with 'aspnetcore_urls'");
                    }
                }
    
                addapplicationservices(applicationservices, hostingserviceprovider);
    
                var host = new webhost(
                    applicationservices,
                    hostingserviceprovider,
                    _options,
                    _config,
                    hostingstartuperrors);
                try
                {
                    host.initialize();
    
                    var logger = host.services.getrequiredservice<ilogger<webhost>>();
    
                    // warn about duplicate hostingstartupassemblies
                    foreach (var assemblyname in _options.getfinalhostingstartupassemblies().groupby(a => a, stringcomparer.ordinalignorecase).where(g => g.count() > 1))
                    {
                        logger.logwarning($"the assembly {assemblyname} was specified multiple times. hosting startup assemblies should only be specified once.");
                    }
    
                    return host;
                }
                catch
                {
                    // dispose the host if there's a failure to initialize, this should clean up
                    // will dispose services that were constructed until the exception was thrown
                    host.dispose();
                    throw;
                }
    
                iserviceprovider getproviderfromfactory(iservicecollection collection)
                {
                    var provider = collection.buildserviceprovider();
                    var factory = provider.getservice<iserviceproviderfactory<iservicecollection>>();
    
                    if (factory != null && !(factory is defaultserviceproviderfactory))
                    {
                        using (provider)
                        {
                            return factory.createserviceprovider(factory.createbuilder(collection));
                        }
                    }
    
                    return provider;
                }
            }

    启动类:startup

    每个asp.net core程序都需要一个启动类,约定命名为:startup。startup用于配置服务和配置http请求管道。

    namespace hellonetcorewebapi
    {
        public class startup
        {
            public startup(iconfiguration configuration)
            {
                configuration = configuration;
            }
    
            public iconfiguration configuration { get; }
    
            // this method gets called by the runtime. use this method to add services to the container.
            public void configureservices(iservicecollection services)
            {
                services.addmvc().setcompatibilityversion(compatibilityversion.version_2_2);
            }
    
            // this method gets called by the runtime. use this method to configure the http request pipeline.
            public void configure(iapplicationbuilder app, ihostingenvironment env)
            {
                if (env.isdevelopment())
                {
                    app.usedeveloperexceptionpage();
                }
                else
                {
                    // the default hsts value is 30 days. you may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                    app.usehsts();
                }
    
                app.usehttpsredirection();
                app.usemvc();
            }
        }
    }

    startup必须包含configure方法, 并选择包含configureservices方法,这两个方法在应用程序启动时调用,该类还可以包含这些方法的特定环境的版本,并且configureservices方法(如果存在)在configure方法之前调用。

    configure方法主要是配置asp.net core的中间件,相当于我们在asp.net中所说的管道,configureservices方法主要是配置依赖注入(di)。