导航

08-003 Hosting 之 StartupLoader : IStartupLoader

Posted on 2015-04-07 10:57  DotNet1010  阅读(146)  评论(0)    收藏  举报

Startup类里主要有两类方法:

一类是: ConfigureServices(IServiceCollection)  这个方法的参数至少有一个 可以为多个 其它的必须可以由依赖注入来创建。

叫做      servicesMethod    (这类方法不是必须的,就是说也可以没有)

格式为:"Configure{0}Services", environmentName    

查找的顺序为:methodNameWithEnv  》 methodNameWithNoEnv .

比如:

public void ConfigureServices(IServiceCollection services)

public void ConfigureDevelopmentServices(IServiceCollection services)

public void ConfigureProductionServices(IServiceCollection services)

public IServiceProvider ConfigureServices(IServiceCollection)  可以是IServiceProvider 这个返回值。

另一类是: Configure(IApplicationBuiler)         这个方法的参数也必须大于等于1.

叫做:     configureMethod

格式为: "Configure{0}", environmentName

比如:

public void Configure(IApplicationBuilder app)

public void ConfigureDevelopment(IApplicationBuilder app, ILoggerFactory loggerFactory)

public void ConfigureStaging(IApplicationBuilder app, ILoggerFactory loggerFactory)

public void ConfigureProduction(IApplicationBuilder app, ILoggerFactory loggerFactory)

Startup类的名字也不是固定的:

            var startupName1 = "Startup" + environmentName;     //这里默认指的是:StartupDevelopment;
            var startupName2 = "Startup";

            // Check the most likely places first
            var type =
                assembly.GetType(startupName1) ??                          
                assembly.GetType(applicationName + "." + startupName1) ??
                assembly.GetType(startupName2) ??
                assembly.GetType(applicationName + "." + startupName2);

 优先级由大到小依次是:

Startup{environmentName}>{applicationName}.Startup{environmentName}>Startup>{applicationName}.Startup

接口代码:

   public interface IStartupLoader
    {
        Action<IApplicationBuilder> LoadStartup(
            string applicationName, 
            string environmentName,
            IList<string> diagnosticMessages);
    }

 核心方法:

       private object Invoke(MethodInfo methodInfo, object instance, IApplicationBuilder builder, IServiceCollection services = null)
        {
            var serviceProvider = builder.ApplicationServices ?? _services;
            var parameterInfos = methodInfo.GetParameters();
            var parameters = new object[parameterInfos.Length];
            for (var index = 0; index != parameterInfos.Length; ++index)
            {
                var parameterInfo = parameterInfos[index];
                if (parameterInfo.ParameterType == typeof(IApplicationBuilder))
                {
                    parameters[index] = builder;
                }
                else if (services != null && parameterInfo.ParameterType == typeof(IServiceCollection))
                {
                    parameters[index] = services;
                }
                else
                {
                    try
                    {
                        parameters[index] = serviceProvider.GetRequiredService(parameterInfo.ParameterType);
                    }
                    catch (Exception)
                    {
                        throw new Exception(string.Format(
                            "TODO: Unable to resolve service for {0} method {1} {2}",
                            methodInfo.Name,
                            parameterInfo.Name,
                            parameterInfo.ParameterType.FullName));
                    }
                }
            }
            return methodInfo.Invoke(instance, parameters);
        }

        public Action<IApplicationBuilder> LoadStartup(
            string applicationName,
            string environmentName,
            IList<string> diagnosticMessages)
        {
            if (String.IsNullOrEmpty(applicationName))
            {
				// 这里最后的一个 next 是 NullStartupLoader LoadStartup 返回 null
				return _next.LoadStartup(applicationName, environmentName, diagnosticMessages);
            }

            var assembly = Assembly.Load(new AssemblyName(applicationName));
            if (assembly == null)
            {
                throw new Exception(String.Format("TODO: assembly {0} failed to load message", applicationName));
            }

			// environmentName= _config.Get("ASPNET_ENV")?? "Development" 可以修改配置文件来切换 
			var startupName1 = "Startup" + environmentName;	 //这里默认指的是:StartupDevelopment;
			var startupName2 = "Startup";

            // Check the most likely places first
            var type =
                assembly.GetType(startupName1) ??                          
                assembly.GetType(applicationName + "." + startupName1) ??
                assembly.GetType(startupName2) ??
                assembly.GetType(applicationName + "." + startupName2);
			// 找不到可能是命名空间的问题 没有完全限定名
            if (type == null)
            {
                // Full scan
                var definedTypes = assembly.DefinedTypes.ToList();

                var startupType1 = definedTypes.Where(info => info.Name.Equals(startupName1, StringComparison.Ordinal));
                var startupType2 = definedTypes.Where(info => info.Name.Equals(startupName2, StringComparison.Ordinal));

                var typeInfo = startupType1.Concat(startupType2).FirstOrDefault();
                if (typeInfo != null)
                {
                    type = typeInfo.AsType();
                }
            }

            if (type == null)
            {
                throw new Exception(String.Format("TODO: {0} or {1} class not found in assembly {2}",
                    startupName1,
                    startupName2,
                    applicationName));
            }

			// 先找类: StartupDevelopment->{APPName}.StartupDevelopment->Startup->{APPName}.Startup
			// // environmentName= _config.Get("ASPNET_ENV")?? "Development" 可以修改配置文件来切换 
			// 默认: ConfigureDevelopment
			// FindMethod 先找  带 environmentName 的 找不到的话 找 不带 environmentName 的方法。
			var configureMethod = FindMethod(type, "Configure{0}", environmentName, typeof(void), required: true);
			// 默认:ConfigureDevelopmentServices
			var servicesMethod = FindMethod(type, "Configure{0}Services", environmentName, typeof(IServiceProvider), required: false)
                ?? FindMethod(type, "Configure{0}Services", environmentName, typeof(void), required: false);

            object instance = null;
            if (!configureMethod.IsStatic || (servicesMethod != null && !servicesMethod.IsStatic))
            {
				//  return provider.GetService(type) ?? CreateInstance(provider, type); 
				// 这里是 StartUp 类
				instance = ActivatorUtilities.GetServiceOrCreateInstance(_services, type);
            }
            return builder =>
            {
                if (servicesMethod != null)
                {
                    var services = HostingServices.Create(builder.ApplicationServices);
                    if (servicesMethod.ReturnType == typeof(IServiceProvider))
                    {
                        // IServiceProvider ConfigureServices(IServiceCollection)  执行此方法
                        builder.ApplicationServices = (Invoke(servicesMethod, instance, builder, services) as IServiceProvider)
                            ?? builder.ApplicationServices; 
                    }
                    else
                    {
                        // void ConfigureServices(IServiceCollection)  执行此方法
                        Invoke(servicesMethod, instance, builder, services);
                        if (builder != null)
                        {
                            builder.ApplicationServices = services.BuildServiceProvider();
                        }
                    }
                }
				// 先执行 ConfigureServices(IServiceCollection services) 方法 如果有        里面的方法主要是    services.Add .....
				// 执行 Configure(IApplicationBuiler)  方法    里面的方法主要是    builder.Use 
				Invoke(configureMethod, instance, builder);
            };
        }