作为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方法