为什么80%的码农都做不了架构师?>>>
作为main函数的程序启动文件UseStartup 默认就是调用我们的整个应用程序的启动文件 class Program{static void Main(string[] args){var host = new WebHostBuilder().UseKestrel() // 指定WebServer为Kestrel.UseStartup<StartUpB>() // 配置WebHost.Build();host.Run(); // 启动WebHost}}
UseStartup
首先这是IWebHostBuilder接口的扩展类,这里有两个分支
1、如果StartUp从IStartup继承,则直接以单例的方式加入插件服务框架中。
2、如果不是从IStartup继承,则包装为IStartup后,再以单例的方式加入插件服务框架中。
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder, Type startupType){var startupAssemblyName = startupType.GetTypeInfo().Assembly.GetName().Name;return hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName).ConfigureServices(services =>{if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo())){services.AddSingleton(typeof(IStartup), startupType);}else{services.AddSingleton(typeof(IStartup), sp =>{var hostingEnvironment = sp.GetRequiredService<IHostingEnvironment>();ConventionBasedStartup类正是继承了IStartup。 LoadMethods 内部调用FindConfigureDelegate 就是为了找到 Configure{0}此方法 public void Configure(IApplicationBuilder app){ }return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName));});}});}
public class ConventionBasedStartup : IStartup{private readonly StartupMethods _methods;public ConventionBasedStartup(StartupMethods methods){_methods = methods;}public void Configure(IApplicationBuilder app){try{_methods.ConfigureDelegate(app);}catch (Exception ex){if (ex is TargetInvocationException){ExceptionDispatchInfo.Capture(ex.InnerException).Throw();}throw;}}public IServiceProvider ConfigureServices(IServiceCollection services){try{return _methods.ConfigureServicesDelegate(services);}catch (Exception ex){if (ex is TargetInvocationException){ExceptionDispatchInfo.Capture(ex.InnerException).Throw();}throw;}}}
public static StartupMethods LoadMethods(IServiceProvider hostingServiceProvider, Type startupType, string environmentName){var configureMethod = FindConfigureDelegate(startupType, environmentName);var servicesMethod = FindConfigureServicesDelegate(startupType, environmentName);object instance = null;if (!configureMethod.MethodInfo.IsStatic || (servicesMethod != null && !servicesMethod.MethodInfo.IsStatic)){instance = ActivatorUtilities.GetServiceOrCreateInstance(hostingServiceProvider, startupType);}Func<IServiceCollection, IServiceProvider> configureServices = services =>{ return services.BuildServiceProvider();};return new StartupMethods(instance, configureMethod.Build(instance), configureServices);}
private static ConfigureBuilder FindConfigureDelegate(Type startupType, string environmentName){var configureMethod = FindMethod(startupType, "Configure{0}", environmentName, typeof(void), required: true);return new ConfigureBuilder(configureMethod);}
这个是源码实现的了一个IStartup 但是在默认的项目中并没有使用这个 正常情况下我们继承StartupBase 此抽象类 实现 Configure(IApplicationBuilder app) 方法就可以了 public abstract class StartupBase : IStartup{public abstract void Configure(IApplicationBuilder app);IServiceProvider IStartup.ConfigureServices(IServiceCollection services){ConfigureServices(services);return CreateServiceProvider(services);}public virtual void ConfigureServices(IServiceCollection services){}public virtual IServiceProvider CreateServiceProvider(IServiceCollection services){return services.BuildServiceProvider();}}
总结最终情况就是:我们的应用程序要启动文件必须满足一下方式就可以了
1、自己定义个类,必须包含Configure方法
2、继承自IStartup,实现所有方法
3、继承自StartupBase抽象类,只需要实现Configure方法