加入收藏 | 设为首页 | 会员中心 | 我要投稿 应用网_阳江站长网 (https://www.0662zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 创业 > 政策 > 正文

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

发布时间:2020-12-11 22:21:37 所属栏目:政策 来源:做站长
导读:这篇文章主要介绍了深入探究ASP.NET Core Startup初始化问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下 前言 Startup类相信大家都比较熟悉,在我们使用ASP.NET Core开发过程中经常用到的类,我们通常使用

相信对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)
{
// 通过这里我们就比较清晰的看出,只有满足这几种情况下才能返回具体的实例,其他的都会返回null
#pragma warning disable CS0618 // Type or member is obsolete
if (serviceType == typeof(Microsoft.Extensions.Hosting.IHostingEnvironment)
|| serviceType == typeof(Microsoft.AspNetCore.Hosting.IHostingEnvironment)
#pragma warning restore CS0618 // Type or member is obsolete
|| serviceType == typeof(IWebHostEnvironment)
|| serviceType == typeof(IHostEnvironment)
)
{
return _context.HostingEnvironment;
}
if (serviceType == typeof(IConfiguration))
{
return _context.Configuration;
}
//不满足这几种情况的类型都返回null
return null;
}
}

通过这个内部私有类我们就能清晰的看到为何Starup的构造函数只能注入IWebHostEnvironment、IHostEnvironment、IConfiguration相关实例了,HostServiceProvider类实现了IServiceProvider的GetService方法并做了判断,只有满足这几种类型才能返回具体的实例注入,其它不满足条件的类型都会返回null。因此在初始化Starup实例的时候,通过构造函数注入的类型也就只能是这几种了。最终通过这个构造函数初始化了Startup类的实例。

ConfigureServices的装载

接下来我们就来在UseStartup方法里继续查看是如何查找并执行ConfigureServices方法的,继续查看找到如下实现[点击查看源码]

//传递startupType和环境变量参数查找返回ConfigureServicesBuilder
var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context.HostingEnvironment.EnvironmentName);
//调用Build方法返回ConfigureServices委托
var configureServices = configureServicesBuilder.Build(instance);
//传递services对象即IServiceCollection对象调用ConfigureServices方法
configureServices(services);

从上述代码中我们可以了解到查找并执行ConfigureServices方法的具体步骤可分为三步,首先在startupType类型中根据环境变量名称查找具体方法返回ConfigureServicesBuilder实例,然后构建ConfigureServicesBuilder实例返回ConfigureServices方法的委托,最后传递IServiceCollection对象执行委托方法。接下来我们就来查看具体实现源码。

我们在StartupLoader类中找到了FindConfigureServicesDelegate方法的相关实现[点击查看源码]

internal static ConfigureServicesBuilder FindConfigureServicesDelegate(Type startupType, string environmentName)
{
//根据startupType和根据environmentName构建的Configure{0}Services字符串先去查找返回类型为IServiceProvider的方法
//找不到在查找返回值为void类型的方法
var servicesMethod = FindMethod(startupType, “Configure{0}Services”, environmentName, typeof(IServiceProvider), required: false)
?? FindMethod(startupType, “Configure{0}Services”, environmentName, typeof(void), required: false);
//根据查找的到的MethodInfo去构建ConfigureServicesBuilder实例
return new ConfigureServicesBuilder(servicesMethod);
}

通过这里的源码我们可以看到在startupType类型里去查找名字为environmentName构建的Configure{0}Services的方法信息,然后根据查找的方法信息即MethodInfo对象去构建ConfigureServicesBuilder实例。接下里我们就来查询FindMethod方法的实现

private static MethodInfo FindMethod(Type startupType, string methodName, string environmentName, Type returnType = null, bool required = true)
{
//包含环境变量的ConfigureServices方法名称比如(ConfigureDevelopmentServices)
var methodNameWithEnv = string.Format(CultureInfo.InvariantCulture, methodName, environmentName);
//名为ConfigureServices的方法
var methodNameWithNoEnv = string.Format(CultureInfo.InvariantCulture, methodName, “”);
//方法是共有的静态的或非静态的方法
var methods = startupType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
//查找包含环境变量的ConfigureServices方法名称
var selectedMethods = methods.Where(method => method.Name.Equals(methodNameWithEnv, StringComparison.OrdinalIgnoreCase)).ToList();
if (selectedMethods.Count > 1)
{
//找打多个满足规则的方法直接抛出异常
throw new InvalidOperationException(string.Format(“Having multiple overloads of method ‘{0}’ is not supported.”, methodNameWithEnv));

(编辑:应用网_阳江站长网)

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

热点阅读