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);
};
}
浙公网安备 33010602011771号