// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.ExceptionServices; using Microsoft.AspNetCore.Hosting.Builder; using Microsoft.AspNetCore.Hosting.Internal; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.AspNetCore.Hosting { /// /// A builder for /// public class WebHostBuilder : IWebHostBuilder { private readonly IHostingEnvironment _hostingEnvironment; private readonly List> _configureServicesDelegates; private readonly List> _configureLoggingDelegates; private IConfiguration _config = new ConfigurationBuilder().AddInMemoryCollection().Build(); private ILoggerFactory _loggerFactory; private WebHostOptions _options; /// /// Initializes a new instance of the class. /// public WebHostBuilder() { _hostingEnvironment = new HostingEnvironment(); _configureServicesDelegates = new List>(); _configureLoggingDelegates = new List>(); // This may end up storing null, but that's indistinguishable from not adding it. UseSetting(WebHostDefaults.EnvironmentKey, Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") // Legacy keys, never remove these. ?? Environment.GetEnvironmentVariable("Hosting:Environment") ?? Environment.GetEnvironmentVariable("ASPNET_ENV")); if (Environment.GetEnvironmentVariable("Hosting:Environment") != null) { Console.WriteLine("The environment variable 'Hosting:Environment' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'"); } if (Environment.GetEnvironmentVariable("ASPNET_ENV") != null) { Console.WriteLine("The environment variable 'ASPNET_ENV' is obsolete and has been replaced with 'ASPNETCORE_ENVIRONMENT'"); } } /// /// Add or replace a setting in the configuration. /// /// The key of the setting to add or replace. /// The value of the setting to add or replace. /// The . public IWebHostBuilder UseSetting(string key, string value) { _config[key] = value; return this; } /// /// Get the setting value from the configuration. /// /// The key of the setting to look up. /// The value the setting currently contains. public string GetSetting(string key) { return _config[key]; } /// /// Specify the to be used by the web host. /// /// The to be used. /// The . public IWebHostBuilder UseLoggerFactory(ILoggerFactory loggerFactory) { if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } _loggerFactory = loggerFactory; return this; } /// /// Adds a delegate for configuring additional services for the host or web application. This may be called /// multiple times. /// /// A delegate for configuring the . /// The . public IWebHostBuilder ConfigureServices(Action configureServices) { if (configureServices == null) { throw new ArgumentNullException(nameof(configureServices)); } _configureServicesDelegates.Add(configureServices); return this; } /// /// Adds a delegate for configuring the provided . This may be called multiple times. /// /// The delegate that configures the . /// The . public IWebHostBuilder ConfigureLogging(Action configureLogging) { if (configureLogging == null) { throw new ArgumentNullException(nameof(configureLogging)); } _configureLoggingDelegates.Add(configureLogging); return this; } /// /// Builds the required services and an which hosts a web application. /// public IWebHost Build() { var hostingServices = BuildHostingServices(); var hostingContainer = hostingServices.BuildServiceProvider(); var host = new WebHost(hostingServices, hostingContainer, _options, _config); host.Initialize(); return host; } 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(); services.AddTransient(); services.AddOptions(); var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore"); services.AddSingleton(diagnosticSource); services.AddSingleton(diagnosticSource); // Conjure up a RequestServices services.AddTransient(); // Ensure object pooling is available everywhere. services.AddSingleton(); 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(); var methods = StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName); return new ConventionBasedStartup(methods); }); } } catch (Exception ex) { var capture = ExceptionDispatchInfo.Capture(ex); services.AddSingleton(_ => { capture.Throw(); return null; }); } } foreach (var configureServices in _configureServicesDelegates) { configureServices(services); } return services; } private string ResolveContentRootPath(string contentRootPath, string basePath) { if (string.IsNullOrEmpty(contentRootPath)) { return basePath; } if (Path.IsPathRooted(contentRootPath)) { return contentRootPath; } return Path.Combine(Path.GetFullPath(basePath), contentRootPath); } } }