public GenericWebHostBuilder(IHostBuilder builder) { _builder = builder; _config = new ConfigurationBuilder() .AddEnvironmentVariables(prefix: "ASPNETCORE_") .Build(); _builder.ConfigureHostConfiguration(config => { config.AddConfiguration(_config); // We do this super early but still late enough that we can process the configuration // wired up by calls to UseSetting ExecuteHostingStartups(); }); // IHostingStartup needs to be executed before any direct methods on the builder // so register these callbacks first _builder.ConfigureAppConfiguration((context, configurationBuilder) => { if (_hostingStartupWebHostBuilder != null) { var webhostContext = GetWebHostBuilderContext(context); _hostingStartupWebHostBuilder.ConfigureAppConfiguration(webhostContext, configurationBuilder); } }); _builder.ConfigureServices((context, services) => { if (_hostingStartupWebHostBuilder != null) { var webhostContext = GetWebHostBuilderContext(context); _hostingStartupWebHostBuilder.ConfigureServices(webhostContext, services); } }); _builder.ConfigureServices((context, services) => { var webhostContext = GetWebHostBuilderContext(context); var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)]; // Add the IHostingEnvironment and IApplicationLifetime from Microsoft.AspNetCore.Hosting services.AddSingleton(webhostContext.HostingEnvironment); services.AddSingleton <IApplicationLifetime, GenericWebHostApplicationLifetime>(); services.Configure <GenericWebHostServiceOptions>(options => { // Set the options options.WebHostOptions = webHostOptions; // Store and forward any startup errors options.HostingStartupExceptions = _hostingStartupErrors; }); services.AddHostedService <GenericWebHostService>(); // REVIEW: This is bad since we don't own this type. Anybody could add one of these and it would mess things up // We need to flow this differently var listener = new DiagnosticListener("Microsoft.AspNetCore"); services.TryAddSingleton <DiagnosticListener>(listener); services.TryAddSingleton <DiagnosticSource>(listener); services.TryAddSingleton <IHttpContextFactory, DefaultHttpContextFactory>(); services.TryAddScoped <IMiddlewareFactory, MiddlewareFactory>(); services.TryAddSingleton <IApplicationBuilderFactory, ApplicationBuilderFactory>(); // Support UseStartup(assemblyName) if (!string.IsNullOrEmpty(webHostOptions.StartupAssembly)) { try { var startupType = StartupLoader.FindStartupType(webHostOptions.StartupAssembly, webhostContext.HostingEnvironment.EnvironmentName); UseStartup(startupType, context, services); } catch (Exception ex) when(webHostOptions.CaptureStartupErrors) { var capture = ExceptionDispatchInfo.Capture(ex); services.Configure <GenericWebHostServiceOptions>(options => { options.ConfigureApplication = app => { // Throw if there was any errors initializing startup capture.Throw(); }; }); } } }); }
private void UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services) { var webHostBuilderContext = GetWebHostBuilderContext(context); var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)]; ExceptionDispatchInfo startupError = null; object instance = null; ConfigureBuilder configureBuilder = null; try { // We cannot support methods that return IServiceProvider as that is terminal and we need ConfigureServices to compose if (typeof(IStartup).IsAssignableFrom(startupType)) { throw new NotSupportedException($"{typeof(IStartup)} isn't supported"); } instance = ActivatorUtilities.CreateInstance(new HostServiceProvider(webHostBuilderContext), startupType); context.Properties[_startupKey] = instance; // Startup.ConfigureServices var configureServicesBuilder = StartupLoader.FindConfigureServicesDelegate(startupType, context.HostingEnvironment.EnvironmentName); var configureServices = configureServicesBuilder.Build(instance); configureServices(services); // REVIEW: We're doing this in the callback so that we have access to the hosting environment // Startup.ConfigureContainer var configureContainerBuilder = StartupLoader.FindConfigureContainerDelegate(startupType, context.HostingEnvironment.EnvironmentName); if (configureContainerBuilder.MethodInfo != null) { var containerType = configureContainerBuilder.GetContainerType(); // Store the builder in the property bag _builder.Properties[typeof(ConfigureContainerBuilder)] = configureContainerBuilder; var actionType = typeof(Action <,>).MakeGenericType(typeof(HostBuilderContext), containerType); // Get the private ConfigureContainer method on this type then close over the container type var configureCallback = GetType().GetMethod(nameof(ConfigureContainer), BindingFlags.NonPublic | BindingFlags.Instance) .MakeGenericMethod(containerType) .CreateDelegate(actionType, this); // _builder.ConfigureContainer<T>(ConfigureContainer); typeof(IHostBuilder).GetMethods().First(m => m.Name == nameof(IHostBuilder.ConfigureContainer)) .MakeGenericMethod(containerType) .Invoke(_builder, new object[] { configureCallback }); } // Resolve Configure after calling ConfigureServices and ConfigureContainer configureBuilder = StartupLoader.FindConfigureDelegate(startupType, context.HostingEnvironment.EnvironmentName); } catch (Exception ex) when(webHostOptions.CaptureStartupErrors) { startupError = ExceptionDispatchInfo.Capture(ex); } // Startup.Configure services.Configure <GenericWebHostServiceOptions>(options => { options.ConfigureApplication = app => { // Throw if there was any errors initializing startup startupError?.Throw(); // Execute Startup.Configure if (instance != null && configureBuilder != null) { configureBuilder.Build(instance)(app); } }; }); }