ASP.NET CORE ---- StartUp分析 (c#, .net, asp.net core, programe加载)

StartUp.cs文件

StartUp.cs中的疑惑点

  • 为什么StartUp.cs中只有ConfigureServices,ConfigureContainer,Configure方法
    • ConfigureServices方法的传入参数只能是IServiceCollection吗?
    • ConfigureContainer方法的传入参数只能是对应三方Di的ContainerBuilder吗?
    • Configure方法的传入参数只能IApplicationBuilder吗?
  • StartUp.cs的构造函数参数只能是IConfiguration吗?
  • StartUp.cs的构造函数参数只有一个参数吗?

了解项目中的StartUp.cs的作用

StartUp.cs作用始点

图(1)

在这里插入图片描述

图(2)

在这里插入图片描述

图(3)

在这里插入图片描述

图(4)

在这里插入图片描述

图(5)

在这里插入图片描述

看到上面那么多框框首先会非常的没抓点,不知道这些框框是在干什么,请先看一下以下对框的解释:

  • 红色框代表的是主流程
  • 蓝色框代表的是 执行UseStartUp()方法的委托方法代码块,在这里先称为 execute委托代码块
  • 绿色框代表的是execute委托代码块又被包了一层委托,在执行execute委托代码块之前先执行一些前置操作,这里层这个委托代码块为enhance委托代码块
  • 黄色框代表的是 构建execute委托代码块execute委托代码块中传入的参数IWebHostBuilder,先称为param委托代码块

解释完之后便可知道,**图(5)**中的内容,先是构造param委托代码块所需要的参数,然后调用param委托代码块获取到IWebHostBuilder,然后执行到enhance委托代码块,再执行到execute委托代码块,从而到UseStartUp<TStartUp>()方法,并可知 webHostBuilder 对应的参数是 GenericWebHostBuilder

加载StartUp.cs

  • 源码(1)

    public static IWebHostBuilder UseStartup<TStartup>(
          this IWebHostBuilder hostBuilder)
          where TStartup : class{
          return hostBuilder.UseStartup(typeof (TStartup));
          }
    
  • 源码(2)

     public static IWebHostBuilder UseStartup(
       this IWebHostBuilder hostBuilder, 
       Type startupType){
        if (hostBuilder is ISupportsStartup supportsStartup)
          return supportsStartup.UseStartup(startupType);
       string name = startupType.Assembly.GetName().Name;
       hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, name);
       return hostBuilder.ConfigureServices((Action<IServiceCollection>) (services =>{
         ///....
          }));
        }
    

    到这会先判断GenericWebHostBuilder是否有实现ISupportsStartup接口,如果有实现则继续执行ISupportsStartup的UseStartup(type)方法,没有的话,则往下走,

    实际上GenericWebHostBuilder实现了ISupportsStartup接口

  • 源码(3)

    在这里插入图片描述

  • 源码(4)

    可以看到绿色框的委托方法会被注册到this._builder中,那他是注册到this._builder哪呢?

    在这里插入图片描述

    在这里插入图片描述

    可以看到注册到了HostBuilder中的_configureServicesActions(在ProGrame.cs中会执行.build()方法就会调用注册到这里的委托方法了)

  • 源码(5)

    此处可解答:
      (1)为什么Startup.cs的方法为什么只能叫Configure{EnvironmentName}Services,Configure{EnvironmentName}Container, Configure{EnvironmentName}
    

    再继续看绿色框的委托方法干了什么

    private void UseStartup(
        Type startupType,
         HostBuilderContext context,
         IServiceCollection services,
         object instance = null){
         WebHostBuilderContext hostBuilderContext = this.GetWebHostBuilderContext(context);
         WebHostOptions property = (WebHostOptions) context.Properties[(object) typeof (WebHostOptions)];
         ExceptionDispatchInfo startupError = (ExceptionDispatchInfo) null;
         ConfigureBuilder configureBuilder = (ConfigureBuilder) null;
         try
         {
           //如果StartUp.cs实现了IStartup接口,则抛异常
           if (typeof (IStartup).IsAssignableFrom(startupType)){
            	//....
              throw new NotSupportedException()
           }
    		//如果StartUp.cs中无 Configure{0}Services 方法则抛出异常
           if (StartupLoader.HasConfigureServicesIServiceProviderDelegate(startupType, context.HostingEnvironment.EnvironmentName))
           {
    				//....
             throw new NotSupportedException()
           }
           //创建StartUp.cs实例,这里在 `源码(6)` 中会进行解析
           if (instance == null)
             instance = ActivatorUtilities.CreateInstance((IServiceProvider) new GenericWebHostBuilder.HostServiceProvider(hostBuilderContext), startupType);
           //保存到HostBuilderContext中。
           context.Properties[this._startupKey] = instance;
           //这里就是反射调用了StartUp.cs的Configure{0}Services方法,在 `源码(7)` 中会进行解析
           IServiceProvider serviceProvider = 
             			StartupLoader.FindConfigureServicesDelegate(
            									startupType, 
             							context.HostingEnvironment.EnvironmentName)
             			.Build(instance)(services);
           
           //这里就是生成反射调用StartUp.cs的Configure{0}Container委托方法,但是未调用此方法
           ConfigureContainerBuilder containerDelegate = 
             			StartupLoader.FindConfigureContainerDelegate(
             								startupType, 
             								context.HostingEnvironment.EnvironmentName);
           
           if (containerDelegate.MethodInfo != (MethodInfo) null)
           {
             this._builder.Properties[(object) typeof (ConfigureContainerBuilder)] = 	
               						(object) containerDelegate;
             //这里就是反射调用了StartUp.cs的Configure{0}Container方法,在`源码(8)` 中进行解析
             InvokeContainer(this, containerDelegate);
           }
           
           //这里就是生成反射调用StartUp.cs的 Configure{0} 委托方法,但是未调用此方法
           configureBuilder = 
             		StartupLoader.FindConfigureDelegate(
             						startupType, 
             						context.HostingEnvironment.EnvironmentName);
         }
         catch (Exception ex) when (property.CaptureStartupErrors)
         {
           startupError = ExceptionDispatchInfo.Capture(ex);
         }
      
         //这里就是反射调用StartUp.cs的 Configure{0} 方法
         services.Configure<GenericWebHostServiceOptions>((Action<GenericWebHostServiceOptions>) (options => options.ConfigureApplication = (Action<IApplicationBuilder>) (app =>
         {
           startupError?.Throw();
           if (instance == null || configureBuilder == null)
             return;
           //此处暂不进行解析
           configureBuilder.Build(instance)(app);
         })));
    
  • 源码(6)

    此处可解答:
      (1)为什么Startup.cs的构造器无法引入其他的类型,只能是IConfiguration,IWebHostEnvironment这些
    
     private void UseStartup(
          Type startupType,
          HostBuilderContext context,
          IServiceCollection services,
          object instance = null){
       		//.....
    				instance = 
              ActivatorUtilities.CreateInstance(
    (IServiceProvider) new GenericWebHostBuilder.HostServiceProvider(hostBuilderContext), 
              startupType);
       		//.....
     }
    

    可以看到他new了一个serviceProvider,但是这个serviceProvider是被重写的,可以看一下GenericWebHostBuilder的实现

    private sealed class HostServiceProvider : IServiceProvider{
    	private readonly WebHostBuilderContext _context;
    	public HostServiceProvider(WebHostBuilderContext context) => this._context = context;
    
     	public object GetService(Type serviceType){
    		if (serviceType == typeof (Microsoft.Extensions.Hosting.IHostingEnvironment) 						|| serviceType == typeof (IHostingEnvironment) 
             || serviceType == typeof (IWebHostEnvironment) 
             || serviceType == typeof (IHostEnvironment))
             	return (object) this._context.HostingEnvironment;
         return serviceType == typeof (IConfiguration) ?
           (object) this._context.Configuration : (object) null;
         }
    }
    

    可以看到他重写了GetService方法,当传入类型为IHostingEnvironment or IHostingEnvironment or IWebHostEnvironment or IHostEnvironment的时候,返回的均为this._context.HostingEnvironment,当传入类型为IConfiguration,返回的是this._context.Configuration 传入其他的就只会为null。

    这里就不具体看 ActivatorUtilities.CreateInstance方法了,该方法实际上就是实例化传入的Type,而传入Type的构造函数参数均由serviceProvider提供,并且注意该Type只能提供一个构造器。

    从上面可得知:

    • StartUp.cs只能有一个构造器
    • StartUp.cs构造器参数只能是IHostingEnvironment or IHostingEnvironment or IWebHostEnvironment or IHostEnvironment or IConfiguration
    • 如果我们获取到全局的serviceProvider,使用用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值