没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
前言 Startup类相信大家都比较熟悉,在我们使用ASP.NET Core开发过程中经常用到的类,我们通常使用它进行IOC服务注册,配置中间件信息等。虽然它不是必须的,但是将这些操作统一在Startup中做处理,会在实际开发中带来许多方便。当我们谈起Startup类的时候你有没有好奇过以下几点 为何我们自定义的Startup可以正常工作。 我们定义的Startup类中ConfigureServices和Configure只能叫这个名字才能被调用到吗? 在使用泛型主机(IHostBuilder)时Startup的构造函数,为何只支持注入IWebHostEnvironment、IHo
资源推荐
资源详情
资源评论
深入探究深入探究ASP.NET Core Startup初始化问题初始化问题
前言前言
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的构造函数的构造函数
相信对Startup有所了解的同学们都比较清楚,在使用泛型主机(IHostBuilder)时Startup的构造函数只支持注入
IWebHostEnvironment、IHostEnvironment、IConfiguration,这个在微软官方文档中https://docs.microsoft.com/en-
us/aspnet/core/fundamentals/startup?view=aspnetcore-3.1也有介绍,如果还有不熟悉这个操作的请先反思一下自己,然后在查
阅微软官方文档。接下来我们就从源码着手,来探究一下它到底是如何做到的。沿着上述的操作,继续查看UseStartup里的代
码找到了如下的实现[点击查看源码]
//创建Startup实例
object instance = ActivatorUtilities.CreateInstance(new HostServiceProvider(webHostBuilderContext), startupType);
这里的startupType就是我们传递的Startup类型,关于ActivatorUtilities这个类还是比较实用的,它为我们提供了许多帮助我们
实例化对象的方法,在日常编程中如果有需要可以使用这个类。上面的ActivatorUtilities的CreateInstance方法的功能就是根据
传递IServiceProvider类型的对象去实例化指定的类型对象,我们这里的类型就是startupType。它的使用场景就是,如果某个
类型需要用过有参构造函数去实例化,而构造函数的参数可以来自于IServiceProvider的实例,那么使用这个方法就在合适不
过了。上面的代码传递的IServiceProvider的实例是HostServiceProvider对象,接下来我们找到它的实现源码[点击查看源码]
代码并不多我们就全部粘贴出来
private class HostServiceProvider : IServiceProvider
{
private readonly WebHostBuilderContext _context;
public HostServiceProvider(WebHostBuilderContext context)
{
_context = context;
}
public object GetService(Type serviceType)
{
剩余7页未读,继续阅读
资源评论
weixin_38575536
- 粉丝: 3
- 资源: 926
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 基于matlab的FFT分析和滤波程序,可对数据信号进行频谱分析,分析波形中所含谐波分量,并可以对特定频率波形进行提取 不需要通过示波器观察,直接导入数据即可,快捷便利 程序带有详细注释, 图a为
- 基于Springboot+Vue的精简博客系统的设计与实现-毕业源码案例设计(源码+论文).zip
- 基于Springboot+Vue交通管理在线服务系统的开发-毕业源码案例设计(95分以上).zip
- uDDS源程序publisher
- 机械手自动排列控制PLC与触摸屏程序设计
- 基于Springboot+Vue的客户关系管理系统(crm)的设计与实现-毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue的课程作业管理系统毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue的酒店客房管理系统-毕业源码案例设计(源码+数据库).zip
- (链家)上海市房屋租赁价格数据.zip
- ESP8266-调试.pdf
- 基于STM32设计的工地扬尘与噪音实时监测系统(网页).pdf
- 基于Springboot+Vue的库存管理系统-毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue的老年人体检管理系统-毕业源码案例设计(高分毕业设计).zip
- 基于Springboot+Vue的乐享田园系统-毕业源码案例设计(95分以上).zip
- 基于Springboot+Vue的流浪宠物管理系统的设计与实现-毕业源码案例设计(95分以上).zip
- 基于Springboot+Vue的论坛系统-毕业源码案例设计(高分项目).zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功