加入收藏 | 设为首页 | 会员中心 | 我要投稿 南平站长网 (https://www.0599zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > Asp教程 > 正文

深入探究ASP.NET Core Startup初始化问题

发布时间:2020-12-10 15:38:47 所属栏目:Asp教程 来源:网络整理
导读:副标题#e# Startup类相信大家都比较熟悉,在我们使用ASP.NET Core开发过程中经常用到的类,我们通常使用它进行IOC服务注册,配置中间件信息等。虽然它不是必须的,但是将这些操作统一在Startup中做处理,会在实际开发中带来许多方便。当我们谈起Startup类的
副标题[/!--empirenews.page--]

Startup类相信大家都比较熟悉,在我们使用ASP.NET Core开发过程中经常用到的类,我们通常使用它进行IOC服务注册,配置中间件信息等。虽然它不是必须的,但是将这些操作统一在Startup中做处理,会在实际开发中带来许多方便。当我们谈起Startup类的时候你有没有好奇过以下几点

为何我们自定义的Startup可以正常工作。

我们定义的Startup类中ConfigureServices和Configure只能叫这个名字才能被调用到吗?

在使用泛型主机(IHostBuilder)时Startup的构造函数,为何只支持注入IWebHostEnvironment、IHostEnvironment、IConfiguration。

ConfigureServices方法为何只能传递IServiceCollection实例。

Configure方法的参数为何可以是所有在IServiceCollection注册服务实例。

在ASP.NET Core结合Autofac使用的时候为何我们添加的ConfigureContainer方法会被调用。

带着以上几点疑问,我们将在本篇文章中探索Startup的源码,来了解Startup初始化过程到底为我们做了些什么。

Startup的另类指定方式

在日常编码过程中,我们通常使用UseStartup的方式来引入Startup类。但是这并不是唯一的方式,还有一种方式是在配置节点中指定Startup所在的程序集来自动查找Startup类,这个我们可以在GenericWebHostBuilder的构造函数源码中的找到相关代码[点击查看源码👈]相信熟悉ASP.Net Core启动流程的同学对GenericWebHostBuilder这个类都比较了解。ConfigureWebHostDefaults方法中其实调用了ConfigureWebHost方法,ConfigureWebHost方法中实例化了GenericWebHostBuilder对象,启动流程不是咱们的重点,所以这里只是简单描述一下。直接找到我们需要的代码如下所示

//判断是否配置了StartupAssembly参数 if (!string.IsNullOrEmpty(webHostOptions.StartupAssembly)) { try { //根据你配置的程序集去查找Startup var startupType = StartupLoader.FindStartupType(webHostOptions.StartupAssembly, webhostContext.HostingEnvironment.EnvironmentName); UseStartup(startupType, context, services); } catch (Exception ex) when (webHostOptions.CaptureStartupErrors) { //此处省略代码省略 } }

这里我们可以看出来,我们需要配置StartupAssembly对应的程序集,它可以通过StartupLoader的FindStartupType方法加载程序集中对应的类。我们还可以看到它还传递了EnvironmentName环境变量,至于它起到了什么作用,我们继续往下看。
首先我们需要找到webHostOptions.StartupAssembly是如何被初始化的,在WebHostOptions的构造函数中我们找到了StartupAssembly初始化的地方[点击查看源码👈]

StartupAssembly = configuration[WebHostDefaults.StartupAssemblyKey];

从这里也可以看出来它的值来于配置,它的key来自WebHostDefaults.StartupAssemblyKey这个常量值,最后我们找到了的值为

public static readonly string StartupAssemblyKey = "startupAssembly";

也就是说只要我们给startupAssembly配置Startup所在的程序集名称,它就可以在程序集中查找Startup类进行初始化,如下所示

public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureHostConfiguration(config=> { List<KeyValuePair<string, string>> keyValuePairs = new List<KeyValuePair<string, string>>(); //配置Startup所在的程序集名称 keyValuePairs.Add(new KeyValuePair<string, string>("startupAssembly", "Startup所在的程序集名称")); config.AddInMemoryCollection(keyValuePairs); }) .ConfigureWebHostDefaults(webBuilder => { //这样的话这里就可以省略了 //webBuilder.UseStartup<Startup>(); });

回到上面的思路,我们在StartupLoader类中查看FindStartupType方法,来看下它是通过什么规则来查找Startup的[点击查看源码👈]精简之后的代码大致如下

public static Type FindStartupType(string startupAssemblyName, string environmentName) { var assembly = Assembly.Load(new AssemblyName(startupAssemblyName)); //名称Startup+环境变量的类比如(StartupDevelopment) var startupNameWithEnv = "Startup" + environmentName; //名称为Startup的类 var startupNameWithoutEnv = "Startup"; // 先查找包含名称Startup+环境变量的相关类,如果找不到则查找名称为Startup的类 var type = assembly.GetType(startupNameWithEnv) ?? assembly.GetType(startupAssemblyName + "." + startupNameWithEnv) ?? assembly.GetType(startupNameWithoutEnv) ?? assembly.GetType(startupAssemblyName + "." + startupNameWithoutEnv); if (type == null) { // 如果上述规则找不到,则在程序集定义的所有类中继续查找 var definedTypes = assembly.DefinedTypes.ToList(); var startupType1 = definedTypes.Where(info => info.Name.Equals(startupNameWithEnv, StringComparison.OrdinalIgnoreCase)); var startupType2 = definedTypes.Where(info => info.Name.Equals(startupNameWithoutEnv, StringComparison.OrdinalIgnoreCase)); var typeInfo = startupType1.Concat(startupType2).FirstOrDefault(); if (typeInfo != null) { type = typeInfo.AsType(); } } //最终返回Startup类型 return type; }

通过上述代码我们可以看到在通过配置指定程序集时是如何查找指定规则的Startup类的,基本上可以理解为先去查找名称为Startup+环境变量的类,如果找不到则继续查找名称为Startup的类,最终会返回Startup的类型传递给UseStartup方法。其实我们最常使用的UseStartup()方法最终也是转换成UseStartup(typeof(T))的方式,所以最终这两种方式走到了相同的地方,接下来我们步入正题,来一起探究一下Starup究竟是如何被初始化的。

Startup的构造函数

(编辑:南平站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读