/// <summary> /// Specify the startup type to be used by the web host. /// </summary> /// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param> /// <param name="startupType">The <see cref="Type"/> to be used.</param> /// <returns>The <see cref="IWebHostBuilder"/>.</returns> 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>(); return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName)); }); } })); }
public static IWebHostBuilder UseStartup <[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TStartup>(this IWebHostBuilder hostBuilder, Func <WebHostBuilderContext, TStartup> startupFactory) where TStartup : class { if (startupFactory == null) { throw new ArgumentNullException(nameof(startupFactory)); } var startupAssemblyName = startupFactory.GetMethodInfo().DeclaringType !.Assembly.GetName().Name; hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, startupAssemblyName); // Light up the GenericWebHostBuilder implementation if (hostBuilder is ISupportsStartup supportsStartup) { return(supportsStartup.UseStartup(startupFactory)); } return(hostBuilder .ConfigureServices((context, services) => { services.AddSingleton(typeof(IStartup), sp => { var instance = startupFactory(context) ?? throw new InvalidOperationException("The specified factory returned null startup instance."); var hostingEnvironment = sp.GetRequiredService <IHostEnvironment>(); // Check if the instance implements IStartup before wrapping if (instance is IStartup startup) { return startup; } return new ConventionBasedStartup(StartupLoader.LoadMethods(sp, instance.GetType(), hostingEnvironment.EnvironmentName, instance)); }); })); }
private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors) { hostingStartupErrors = null; _options = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name); if (!_options.PreventHostingStartup) { var exceptions = new List <Exception>(); // Execute the hosting startup assemblies foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies().Distinct(StringComparer.OrdinalIgnoreCase)) { try { var assembly = Assembly.Load(new AssemblyName(assemblyName)); foreach (var attribute in assembly.GetCustomAttributes <HostingStartupAttribute>()) { var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType); hostingStartup.Configure(this); } } catch (Exception ex) { // Capture any errors that happen during startup exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex)); } } if (exceptions.Count > 0) { hostingStartupErrors = new AggregateException(exceptions); } } var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory); // Initialize the hosting environment _hostingEnvironment.Initialize(contentRootPath, _options); _context.HostingEnvironment = _hostingEnvironment; var services = new ServiceCollection(); services.AddSingleton(_options); services.AddSingleton <IHostingEnvironment>(_hostingEnvironment); services.AddSingleton <Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment); services.AddSingleton(_context); var builder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddConfiguration(_config); _configureAppConfigurationBuilder?.Invoke(_context, builder); var configuration = builder.Build(); services.AddSingleton <IConfiguration>(configuration); _context.Configuration = configuration; var listener = new DiagnosticListener("Microsoft.AspNetCore"); services.AddSingleton <DiagnosticListener>(listener); services.AddSingleton <DiagnosticSource>(listener); services.AddTransient <IApplicationBuilderFactory, ApplicationBuilderFactory>(); services.AddTransient <IHttpContextFactory, HttpContextFactory>(); services.AddScoped <IMiddlewareFactory, MiddlewareFactory>(); services.AddOptions(); services.AddLogging(); // Conjure up a RequestServices services.AddTransient <IStartupFilter, AutoRequestServicesStartupFilter>(); services.AddTransient <IServiceProviderFactory <IServiceCollection>, DefaultServiceProviderFactory>(); // Ensure object pooling is available everywhere. services.AddSingleton <ObjectPoolProvider, DefaultObjectPoolProvider>(); if (!string.IsNullOrEmpty(_options.StartupAssembly)) { try { var startupType = StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName); if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo())) { services.AddSingleton(typeof(IStartup), startupType); } else { services.AddSingleton(typeof(IStartup), sp => { var hostingEnvironment = sp.GetRequiredService <IHostingEnvironment>(); var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName); return(new ConventionBasedStartup(methods)); }); } } catch (Exception ex) { var capture = ExceptionDispatchInfo.Capture(ex); services.AddSingleton <IStartup>(_ => { capture.Throw(); return(null); }); } } _configureServices?.Invoke(_context, services); return(services); }
private IServiceCollection BuildHostingServices() { _options = new WebHostOptions(_config); var appEnvironment = PlatformServices.Default.Application; var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, appEnvironment.ApplicationBasePath); var applicationName = _options.ApplicationName ?? appEnvironment.ApplicationName; // Initialize the hosting environment _hostingEnvironment.Initialize(applicationName, contentRootPath, _options); var services = new ServiceCollection(); services.AddSingleton(_hostingEnvironment); if (_loggerFactory == null) { _loggerFactory = new LoggerFactory(); } foreach (var configureLogging in _configureLoggingDelegates) { configureLogging(_loggerFactory); } //The configured ILoggerFactory is added as a singleton here. AddLogging below will not add an additional one. services.AddSingleton(_loggerFactory); //This is required to add ILogger of T. services.AddLogging(); services.AddTransient <IApplicationBuilderFactory, ApplicationBuilderFactory>(); services.AddTransient <IHttpContextFactory, HttpContextFactory>(); services.AddOptions(); var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore"); services.AddSingleton <DiagnosticSource>(diagnosticSource); services.AddSingleton <DiagnosticListener>(diagnosticSource); // Conjure up a RequestServices services.AddTransient <IStartupFilter, AutoRequestServicesStartupFilter>(); // Ensure object pooling is available everywhere. services.AddSingleton <ObjectPoolProvider, DefaultObjectPoolProvider>(); if (!string.IsNullOrEmpty(_options.ServerAssembly)) { // Add the server try { var serverType = ServerLoader.ResolveServerType(_options.ServerAssembly); services.AddSingleton(typeof(IServer), serverType); } catch (Exception ex) { var capture = ExceptionDispatchInfo.Capture(ex); services.AddSingleton <IServer>(_ => { capture.Throw(); return(null); }); } } if (!string.IsNullOrEmpty(_options.StartupAssembly)) { try { var startupType = StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName); if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo())) { services.AddSingleton(typeof(IStartup), startupType); } else { services.AddSingleton(typeof(IStartup), sp => { var hostingEnvironment = sp.GetRequiredService <IHostingEnvironment>(); var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName); return(new ConventionBasedStartup(methods)); }); } } catch (Exception ex) { var capture = ExceptionDispatchInfo.Capture(ex); services.AddSingleton <IStartup>(_ => { capture.Throw(); return(null); }); } } foreach (var configureServices in _configureServicesDelegates) { configureServices(services); } return(services); }
private IServiceCollection BuildCommonServices(out AggregateException?hostingStartupErrors) { hostingStartupErrors = null; _options = new WebHostOptions(_config, Assembly.GetEntryAssembly()?.GetName().Name ?? string.Empty); if (!_options.PreventHostingStartup) { var exceptions = new List <Exception>(); var processed = new HashSet <Assembly>(); // Execute the hosting startup assemblies foreach (var assemblyName in _options.GetFinalHostingStartupAssemblies()) { try { var assembly = Assembly.Load(new AssemblyName(assemblyName)); if (!processed.Add(assembly)) { // Already processed, skip it continue; } foreach (var attribute in assembly.GetCustomAttributes <HostingStartupAttribute>()) { var hostingStartup = (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType) !; hostingStartup.Configure(this); } } catch (Exception ex) { // Capture any errors that happen during startup exceptions.Add(new InvalidOperationException($"Startup assembly {assemblyName} failed to execute. See the inner exception for more details.", ex)); } } if (exceptions.Count > 0) { hostingStartupErrors = new AggregateException(exceptions); } } var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, AppContext.BaseDirectory); // Initialize the hosting environment ((IWebHostEnvironment)_hostingEnvironment).Initialize(contentRootPath, _options); _context.HostingEnvironment = _hostingEnvironment; var services = new ServiceCollection(); services.AddSingleton(_options); services.AddSingleton <IWebHostEnvironment>(_hostingEnvironment); services.AddSingleton <IHostEnvironment>(_hostingEnvironment); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton <AspNetCore.Hosting.IHostingEnvironment>(_hostingEnvironment); services.AddSingleton <Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment); #pragma warning restore CS0618 // Type or member is obsolete services.AddSingleton(_context); var builder = new ConfigurationBuilder() .SetBasePath(_hostingEnvironment.ContentRootPath) .AddConfiguration(_config, shouldDisposeConfiguration: true); _configureAppConfigurationBuilder?.Invoke(_context, builder); var configuration = builder.Build(); // register configuration as factory to make it dispose with the service provider services.AddSingleton <IConfiguration>(_ => configuration); _context.Configuration = configuration; services.TryAddSingleton(sp => new DiagnosticListener("Microsoft.AspNetCore")); services.TryAddSingleton <DiagnosticSource>(sp => sp.GetRequiredService <DiagnosticListener>()); services.TryAddSingleton(sp => new ActivitySource("Microsoft.AspNetCore")); services.AddTransient <IApplicationBuilderFactory, ApplicationBuilderFactory>(); services.AddTransient <IHttpContextFactory, DefaultHttpContextFactory>(); services.AddScoped <IMiddlewareFactory, MiddlewareFactory>(); services.AddOptions(); services.AddLogging(); services.AddTransient <IServiceProviderFactory <IServiceCollection>, DefaultServiceProviderFactory>(); if (!string.IsNullOrEmpty(_options.StartupAssembly)) { try { var startupType = StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName); if (typeof(IStartup).IsAssignableFrom(startupType)) { services.AddSingleton(typeof(IStartup), startupType); } else { services.AddSingleton(typeof(IStartup), sp => { var hostingEnvironment = sp.GetRequiredService <IHostEnvironment>(); var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName); return(new ConventionBasedStartup(methods)); }); } } catch (Exception ex) { var capture = ExceptionDispatchInfo.Capture(ex); services.AddSingleton <IStartup>(_ => { capture.Throw(); return(null); }); } } _configureServices?.Invoke(_context, services); return(services); }
public GenericWebHostBuilder(IHostBuilder builder, WebHostBuilderOptions options) { _builder = builder; var configBuilder = new ConfigurationBuilder() .AddInMemoryCollection(); if (!options.SuppressEnvironmentConfiguration) { configBuilder.AddEnvironmentVariables(prefix: "ASPNETCORE_"); } _config = configBuilder.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) => { var webhostContext = GetWebHostBuilderContext(context); var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)]; // Add the IHostingEnvironment and IApplicationLifetime from Microsoft.AspNetCore.Hosting services.AddSingleton(webhostContext.HostingEnvironment); #pragma warning disable CS0618 // Type or member is obsolete services.AddSingleton((AspNetCore.Hosting.IHostingEnvironment)webhostContext.HostingEnvironment); services.AddSingleton <IApplicationLifetime, GenericWebHostApplicationLifetime>(); #pragma warning restore CS0618 // Type or member is obsolete services.Configure <GenericWebHostServiceOptions>(options => { // Set the options options.WebHostOptions = webHostOptions; // Store and forward any startup errors options.HostingStartupExceptions = _hostingStartupErrors; }); // 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>(); // IMPORTANT: This needs to run *before* direct calls on the builder (like UseStartup) _hostingStartupWebHostBuilder?.ConfigureServices(webhostContext, services); // 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([DynamicallyAccessedMembers(StartupLinkerOptions.Accessibility)] Type startupType, HostBuilderContext context, IServiceCollection services, object?instance = null) { var webHostBuilderContext = GetWebHostBuilderContext(context); var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)]; ExceptionDispatchInfo?startupError = 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"); } if (StartupLoader.HasConfigureServicesIServiceProviderDelegate(startupType, context.HostingEnvironment.EnvironmentName)) { throw new NotSupportedException($"ConfigureServices returning an {typeof(IServiceProvider)} 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 = typeof(GenericWebHostBuilder).GetMethod(nameof(ConfigureContainerImpl), BindingFlags.NonPublic | BindingFlags.Instance) ! .MakeGenericMethod(containerType) .CreateDelegate(actionType, this); // _builder.ConfigureContainer<T>(ConfigureContainer); typeof(IHostBuilder).GetMethod(nameof(IHostBuilder.ConfigureContainer)) ! .MakeGenericMethod(containerType) .InvokeWithoutWrappingExceptions(_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); } }; }); }