当前位置:首页 > 技术 > 正文内容

深入解析ASP.NET Core主机启动机制与工作流程

访客 技术 2026年6月10日 1

当开发者将传统ASP.NET应用迁移至ASP.NET Core平台时,会发现项目结构中出现了两个关键类:Program类和Startup类。本文将详细探讨ASP.NET Core中通用主机(Host)的启动机制。

一、Program类入口点分析

Program类的核心职责在于初始化并启动应用程序主机,这是ASP.NET Core引入的一个全新概念。

主机承担着应用程序生命周期管理和资源封装的重要角色,主要包括以下功能组件:

  • 依赖注入(DI)容器
  • 日志记录系统
  • 配置管理
  • 后台服务(IHostedService)实现

当主机启动时,会在DI容器中查找所有IHostedService接口的实现,并依次调用其StartAsync方法。在Web应用场景中,其中一个IHostedService实现负责启动HTTP服务器,默认情况下使用Kestrel作为Web服务器。

简而言之,ASP.NET Core主机启动时会自动初始化一个HTTP服务器(Kestrel),该服务器随后会监听指定端口并处理HTTP请求。

让我们看一下Program类的典型实现:

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>();
            });
}

从上述代码可以看出,Main函数首先调用CreateHostBuilder方法创建并配置主机构建器,然后通过Build方法生成主机实例,最后调用Run方法启动应用程序。

二、Host.CreateDefaultBuilder:构建主机默认配置

CreateHostBuilder方法内部调用了Host.CreateDefaultBuilder来构造一个HostBuilder实例。让我们深入分析这个方法内部实现:

public static IHostBuilder CreateDefaultBuilder(string[] args)
{
    var builder = new HostBuilder();

    // 设置内容根目录
    builder.UseContentRoot(Directory.GetCurrentDirectory());
    
    // 配置主机设置
    builder.ConfigureHostConfiguration(config =>
    {
        config.AddEnvironmentVariables(prefix: "DOTNET_");
        if (args != null)
        {
            config.AddCommandLine(args);
        }
    });

    // 配置应用程序设置
    builder.ConfigureAppConfiguration((hostingContext, config) =>
    {
        var env = hostingContext.HostingEnvironment;

        // 添加JSON配置文件
        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

        // 开发环境下添加用户机密
        if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
        {
            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) =>
    {
        var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

        // Windows环境下默认只记录警告及以上级别的日志
        if (isWindows)
        {
            logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
        }

        // 配置日志提供程序
        logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
        logging.AddConsole();
        logging.AddDebug();
        logging.AddEventSourceLogger();

        if (isWindows)
        {
            logging.AddEventLog();
        }
    })
    .UseDefaultServiceProvider((context, options) =>
    {
        var isDevelopment = context.HostingEnvironment.IsDevelopment();
        options.ValidateScopes = isDevelopment;
        options.ValidateOnBuild = isDevelopment;
    });

    return builder;
}

上述代码展示了CreateDefaultBuilder方法如何配置主机的各个核心组件:

  1. 设置内容根目录为当前工作目录
  2. 通过环境变量(DOTNET_前缀)和命令行参数加载主机配置
  3. 从appsettings.json及相关环境配置文件加载应用配置
  4. 在开发环境下启用用户机密管理
  5. 配置多种日志提供程序(控制台、调试、EventSource等)
  6. 根据环境设置依赖注入验证选项

三、ConfigureWebHostDefaults:配置Web主机特定设置

完成HostBuilder的基本配置后,对于ASP.NET Core Web应用,代码会继续调用ConfigureWebHostDefaults方法来添加Web特定的运行时配置:

public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure)
{
    return builder.ConfigureWebHost(webHostBuilder =>
    {
        WebHost.ConfigureWebDefaults(webHostBuilder);
        configure(webHostBuilder);
    });
}

该方法主要执行以下操作:

  1. 扩展IHostBuilder,注入IWebHostBuilder实现(GenericWebHostBuilder)
  2. 调用WebHost.ConfigureWebDefaults设置Web默认配置
  3. 执行用户自定义的Web配置

让我们看看ConfigureWebDefaults方法的具体实现:

internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
    // 配置应用程序设置
    builder.ConfigureAppConfiguration((ctx, cb) =>
    {
        if (ctx.HostingEnvironment.IsDevelopment())
        {
            StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
        }
    });
    
    // 配置Kestrel服务器
    builder.UseKestrel((builderContext, options) =>
    {
        options.Configure(builderContext.Configuration.GetSection("Kestrel"));
    })
    .ConfigureServices((hostingContext, services) =>
    {
        // 配置主机筛选中间件
        services.PostConfigure<HostFilteringOptions>(options =>
        {
            if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
            {
                var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
            }
        });
        
        services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
                    new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
        services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();

        // 配置转发头中间件
        if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
        {
            services.Configure<ForwardedHeadersOptions>(options =>
            {
                options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
                options.KnownNetworks.Clear();
                options.KnownProxies.Clear();
            });

            services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
        }

        // 添加路由服务
        services.AddRouting();
    })
    .UseIIS()
    .UseIISIntegration();
}

此方法完成了以下Web特定配置:

  1. 在开发环境下加载静态Web资源
  2. 将Kestrel配置为默认Web服务器
  3. 添加主机筛选中间件
  4. 根据配置添加转发头中间件
  5. 启用IIS集成

四、Build与Run:主机构建与启动

最后,我们分析CreateHostBuilder(args).Build().Run()的过程。

Build方法负责完成主机构建,主要步骤包括:

  1. 构建配置系统
  2. 创建主机环境信息
  3. 建立主机构建上下文
  4. 构建应用程序配置
  5. 创建依赖注入服务提供程序

Run方法则是启动主机,内部调用StartAsync方法,初始化所有已注册的服务并开始监听请求。

整个ASP.NET Core主机启动过程涉及多个组件的协同工作,理解这一机制有助于开发者更好地优化应用程序性能和解决启动过程中可能遇到的问题。

标签: ASP.NET Core

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。