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,使用用
ActivatorUtilities.CreateInstance方法去手动创建一个Type实例或者自己重写IServiceProvider去控制对于一个type的构建参

最低0.47元/天 解锁文章
3339

被折叠的 条评论
为什么被折叠?



