首页 > 编程语言 >asp .net core 启动过程

asp .net core 启动过程

时间:2024-08-07 17:28:59浏览次数:14  
标签:core asp builder private var services new net public

1.要了解启动过程,先介绍 IHostingStartup和IStartup 接口

/// <summary>
/// Represents platform specific configuration that will be applied to a <see cref="IWebHostBuilder"/> when building an <see cref="IWebHost"/>.
/// </summary>
public interface IHostingStartup
{
    /// <summary>
    /// Configure the <see cref="IWebHostBuilder"/>.
    /// </summary>
    /// <remarks>
    /// Configure is intended to be called before user code, allowing a user to overwrite any changes made.
    /// </remarks>
    /// <param name="builder"></param>
    void Configure(IWebHostBuilder builder);
}
/// <summary>
/// Provides an interface for initializing services and middleware used by an application.
/// </summary>
public interface IStartup
{
    /// <summary>
    /// Register services into the <see cref="IServiceCollection" />.
    /// </summary>
    /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
    IServiceProvider ConfigureServices(IServiceCollection services);

    /// <summary>
    /// Configures the application.
    /// </summary>
    /// <param name="app">An <see cref="IApplicationBuilder"/> for the app to configure.</param>
    void Configure(IApplicationBuilder app);
}
IHostingStartup 用以配置 IWebHostBuilder,.net core 允许有多个 IHostingStartup得实现来在不同得地方配置 WebHostBuilder,下面展示一下 IHostingStartup得调用过程。
项目启动首先会执行Program.cs文件中的 Main方法,Program文件只是默认项,可以通过更改项目配置 来实现调用指定类的Main方法,
namespace SampleStartups;
public class Program
{
    public static void Main(string[] args)
    {
       
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        return new WebHostBuilder()
            .UseKestrel(opt =>
            {
                opt.AddServerHeader = false;
                opt.Limits.MaxRequestLineSize = 16 * 1024;
            })
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<InjectedStartup>(); 
    }
}

例1:例子来源.net core 8.0 源码 中 Hosting 的SampleStartups

项目配置

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
    <StartupObject>SampleStartups.StartupBlockingOnStart</StartupObject>
    <OutputType>exe</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Microsoft.AspNetCore.Hosting" />
    <Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
    <Reference Include="Microsoft.Extensions.Configuration.CommandLine" />
    <Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
    <Reference Include="Microsoft.Extensions.Configuration.Json" />
  </ItemGroup>
</Project>

通过配置 <StartupObject></StartupObject> 程序启动文件为 SampleStartups.StartupBlockingOnStart

namespace SampleStartups;

public class StartupInjection : IHostingStartup
{
    public void Configure(IWebHostBuilder builder)
    {
        builder.UseStartup<InjectedStartup>();
    }

    // Entry point for the application.
    public static Task Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureWebHost(webHostBuilder =>
            {
                webHostBuilder
                    .UseKestrel()
                    // Each of these three sets ApplicationName to the current assembly, which is needed in order to
                    // scan the assembly for HostingStartupAttributes.
                    // .UseSetting(WebHostDefaults.ApplicationKey, "SampleStartups")
                    // .Configure(_ => { })
                    .UseStartup<NormalStartup>();
            })
            .Build();

        return host.RunAsync();
    }
}

 

HostBuilder.ConfigureXXX

在了解WebHostBuilder之前,大家要先了解HostBuilder一下ConfigureHostConfigurationConfigureAppConfigurationConfigureServices等方法到底做了什么。其实就是将Action暂存到了一个私有属性变量中,
并没有立即执行。
先存在一个list中,后边按一定顺序执行。稍后会介绍在哪里执行这些Action
public class HostBuilder : IHostBuilder
{
    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>>();

    public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
    {
        _configureHostConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
        return this;
    }
    
    public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
    {
        _configureAppConfigActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
        return this;
    }
        
    public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
    {
        _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
        return this;
    }
}

我们看一下  new HostBuilder().ConfigureWebHost(Action<IWebHostBuilder>  configure) 中  ConfigureWebHost() 方法中具体执行了什么  ,

private static IHostBuilder ConfigureWebHost(
        this IHostBuilder builder,
        Func<IHostBuilder, WebHostBuilderOptions, IWebHostBuilder> createWebHostBuilder,
        Action<IWebHostBuilder> configure,
        Action<WebHostBuilderOptions> configureWebHostBuilder)
    {
        ArgumentNullException.ThrowIfNull(configure);
        ArgumentNullException.ThrowIfNull(configureWebHostBuilder);

     //先不介绍这里
        // Light up custom implementations namely ConfigureHostBuilder which throws.
        if (builder is ISupportsConfigureWebHost supportsConfigureWebHost)
        {
            return supportsConfigureWebHost.ConfigureWebHost(configure, configureWebHostBuilder);
        }
     //重点看下这里
        var webHostBuilderOptions = new WebHostBuilderOptions();
        configureWebHostBuilder(webHostBuilderOptions);
     //这里创建了webhostBuilder对象,并立即执行传入的action
        var webhostBuilder = createWebHostBuilder(builder, webHostBuilderOptions);
     //执行传入的action
        configure(webhostBuilder);
     //此处暂存了一个action ,其实在  createWebHostBuilder(builder, webHostBuilderOptions) 中已经执行了逻辑,暂存多个关键的action
     builder.ConfigureServices((context, services) => services.AddHostedService<GenericWebHostService>());
     return builder; 
  }

 

我们看一下在  new GenericWebHostBuilder(hostBuilder, options)  中执行的逻辑

 

internal sealed class GenericWebHostBuilder : WebHostBuilderBase, ISupportsStartup
{
   //用于暂存关于IStartup的相关类型,
    private object? _startupObject;
    private readonly object _startupKey = new object();

    private AggregateException? _hostingStartupErrors;
    private HostingStartupWebHostBuilder? _hostingStartupWebHostBuilder;

    public GenericWebHostBuilder(IHostBuilder builder, WebHostBuilderOptions options)
        : base(builder, options)
    {
     //暂存一个HostConfigration的action 
      
        _builder.ConfigureHostConfiguration(config =>
        {
            config.AddConfiguration(_config);
       //重点关注下这里,稍后介绍
            // We do this super early but still late enough that we can process the configuration
            // wired up by calls to UseSetting
            ExecuteHostingStartups();
        });
        //暂存
        // IHostingStartup needs to be executed before any direct methods on the builder
        // so register these callbacks first
        _builder.ConfigureAppConfiguration((context, configurationBuilder) =>
        {
            if (_hostingStartupWebHostBuilder != null)
            {
                var webhostContext = GetWebHostBuilderContext(context);
                _hostingStartupWebHostBuilder.ConfigureAppConfiguration(webhostContext, configurationBuilder);
            }
        });
    //暂存CongfigureServices action
        _builder.ConfigureServices((context, services) =>
        {
            var webhostContext = GetWebHostBuilderContext(context);
            var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];

            // Add the IHostingEnvironment and IApplicationLifetime from Microsoft.AspNetCore.Hosting
            services.AddSingleton(webhostContext.HostingEnvironment);
#pragma warning disable CS0618 // Type or member is obsolete
            services.AddSingleton((AspNetCore.Hosting.IHostingEnvironment)webhostContext.HostingEnvironment);
            services.AddSingleton<IApplicationLifetime, GenericWebHostApplicationLifetime>();
#pragma warning restore CS0618 // Type or member is obsolete

            services.Configure<GenericWebHostServiceOptions>(options =>
            {
                // Set the options
                options.WebHostOptions = webHostOptions;
                // Store and forward any startup errors
                options.HostingStartupExceptions = _hostingStartupErrors;
            });

            // REVIEW: This is bad since we don't own this type. Anybody could add one of these and it would mess things up
            // We need to flow this differently
            services.TryAddSingleton(sp => new DiagnosticListener("Microsoft.AspNetCore"));
            services.TryAddSingleton<DiagnosticSource>(sp => sp.GetRequiredService<DiagnosticListener>());
            services.TryAddSingleton(sp => new ActivitySource("Microsoft.AspNetCore"));
            services.TryAddSingleton(DistributedContextPropagator.Current);

            services.TryAddSingleton<IHttpContextFactory, DefaultHttpContextFactory>();
            services.TryAddScoped<IMiddlewareFactory, MiddlewareFactory>();
            services.TryAddSingleton<IApplicationBuilderFactory, ApplicationBuilderFactory>();

            services.AddMetrics();
            services.TryAddSingleton<HostingMetrics>();

            // IMPORTANT: This needs to run *before* direct calls on the builder (like UseStartup)
            _hostingStartupWebHostBuilder?.ConfigureServices(webhostContext, services);
        //如果特别指定了startupAssembly ,程序就会扫描程序集获取,这个行为也被暂存在当前的这个action 
            // Support UseStartup(assemblyName)
            if (!string.IsNullOrEmpty(webHostOptions.StartupAssembly))
            {
                ScanAssemblyAndRegisterStartup(context, services, webhostContext, webHostOptions);
            }
        });
    }

  //删除部分代码
}

在webHostBuilder创建过程中暂存了ConfigureHostConfiguration,ConfigureAppConfiguration,ConfigureServices,那么他们都在什么时候执行,并且是一个什么执行顺序。这就要看一下他们在HostBuilder 中Build过程中的执行顺序了,不废话,直接上代码

public class HostBuilder : IHostBuilder
{
    public IHost Build()
    {
        // 加载主机(Host)配置
        BuildHostConfiguration();
        // 实例化 HostingEnvironment
        CreateHostingEnvironment();
        // 实例化 HostBuilderContext
        CreateHostBuilderContext();
        // 加载应用(App)配置
        BuildAppConfiguration();
        // 注册服务并创建 Service Provider
        CreateServiceProvider();
    
        // 生成 IHost 实例并返回
        return _appServices.GetRequiredService<IHost>();
    }
}

不难看出 在 BuildHostConfiguration()方法中,会执行在上面介绍 new WebHostBuilder() 构造函数中暂存的一个action ,看下方代码暂存的那个action

 //暂存一个HostConfigration的action 
      
        _builder.ConfigureHostConfiguration(config =>
        {
            config.AddConfiguration(_config);
       //重点关注下这里,稍后介绍
            // We do this super early but still late enough that we can process the configuration
            // wired up by calls to UseSetting
            ExecuteHostingStartups();
        });

此时为执行 ExecuteHostingStartups,此处涉及执行 HostStartup相关逻辑。

internal sealed class GenericWebHostBuilder : WebHostBuilderBase, ISupportsStartup
{
    private object? _startupObject;
    private readonly object _startupKey = new object();

    private AggregateException? _hostingStartupErrors;
    private HostingStartupWebHostBuilder? _hostingStartupWebHostBuilder;
private void ExecuteHostingStartups() { var webHostOptions = new WebHostOptions(_config); if (webHostOptions.PreventHostingStartup) { return; } var exceptions = new List<Exception>(); var processed = new HashSet<Assembly>(); _hostingStartupWebHostBuilder = new HostingStartupWebHostBuilder(this); // Execute the hosting startup assemblies foreach (var assemblyName in webHostOptions.GetFinalHostingStartupAssemblies()) { try { var assembly = Assembly.Load(new AssemblyName(assemblyName)); if (!processed.Add(assembly)) { // Already processed, skip it continue; } foreach (var attribute in assembly.GetCustomAttributes<HostingStartupAttribute>()) { var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType)!; hostingStartup.Configure(_hostingStartupWebHostBuilder); } } catch (Exception ex) { // Capture any errors that happen during startup exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex)); } } if (exceptions.Count > 0) { _hostingStartupErrors = new AggregateException(exceptions); } } }

 

 

 

 



 

标签:core,asp,builder,private,var,services,new,net,public
From: https://www.cnblogs.com/871735097-/p/18347495

相关文章

  • ASP.NET Core 鉴权授权四(自定义Session)
    实体模型publicclassBaseModel{publicintId{get;set;}}publicclassAuthorization:BaseModel{publicstringRoute{get;set;}publicstringAuthorizationName{get;set;}}publicclassUser:BaseModel{publicstringUserName{......
  • 使用QNetworkAccessManager实现FTP上传下载功能
    自己写了一份FTP的代码,可以上传下载单文件,上传下载多文件,上传目录所有文件,但是下载目录的功能有问题,接口里代码规范也没做(如果有大佬提供修改方案就更好了),代码直接复制可用,留给有需要的人。#pragmaonce#include<QObject>#include<QNetworkReply>#include<QNetworkAcce......
  • Docker部署.netCore6
    Docker部署.netCore6第一步:在项目添加Docker支持第二步:选择Windows(如果是linx系统就选择linx)和Dockerfile第三步:生成Docker默认文件 把默认代码修改第四步:修改Dockerfile文件属性(如果不修改则会导致发布的时候Docker文件没有一起发布)第五步:把项目发布到文件夹在发......
  • EF Core连接PostgreSQL数据库
    PostgreSQL数据库介绍PostgreSQL是一个功能强大的开源对象关系型数据库管理系统(RDBMS)。最初于1986年在加州大学伯克利分校的POSTGRES项目中诞生,PostgreSQL以其稳定性、灵活性和扩展性而著称。它支持丰富的数据类型、复杂的查询、事务完整性、多版本并发控制(MVCC)、存储过程等高级......
  • 处理程序“aspx”在其模块列表中有一个错误模块“ManagedPipelineHandler”
    原文链接:https://www.cnblogs.com/mingcaoyouxin/p/3926800.html开发web项目时需要安装IIS,在安装好IIS的Windows7本上发布asp.net网站时,web程序已经映射到了本地IIS上,但运行如下错误提示“处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPip......
  • k8s学习笔记之CoreDNS
    一、CoreDNSconfigMap配置参数及说明主要讲解CoreDNSconfigMap及其他关键配置部署文件(需要替换其中一些变量):https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/dns/coredns/coredns.yaml.base1.configMap配置apiVersion:v1kind:ConfigMapmetadat......
  • c# net6创建API项目 日志管理log4net的用法
    一、program.cs//配置log4netXmlConfigurator.Configure(newFileInfo("log4net.config"));二、公共类LogHelper.csnamespaceElecInvoice.Common{publicclassLogHelper{publicstaticreadonlylog4net.ILogloginfo=log4net.LogManage......
  • 泗博MODBUS TCP转PROFINET网关EPN-330实现焊机与西门子PLC的连接
    随着工业自动化水平的不断提高,各种设备之间的互联互通变得至关重要。然而,由于不同设备可能采用不同的通信协议,如何实现它们之间的无缝连接,成为了许多工程师和企业面临的难题。今天,我们就来分享一个上海泗博成功的案例,看看如何通过泗博自动化的MODBUSTCP转PROFINET网关EPN-330,实现......
  • .NET 免费开源工业物联网网关
    前言IoTClient是一个针对物联网(IoT)领域的开源客户端库,它主要用于实现与各种工业设备之间的通信。这个库是用C#编写的,并且基于.NETStandard2.0,这意味着可以用于多个版本的.NET,包括.NETFramework、.NETCore、.NET5及以上版本,以及Xamarin和UWP。项目介绍IoTClie......
  • 解决电脑缺少.NET组件?手把手教你轻松解决
    在日常使用电脑的过程中,很多用户可能会遇到“电脑缺少.NET组件”的提示,这可能导致某些应用程序无法正常运行或安装。那么,.NET组件到底是什么?为何它如此重要?本文将为您详细解答这些问题,并提供有效的解决方案,帮助您快速修复这一常见问题。一.什么是.NET组件?.NET组件是由微软开......