// 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 Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting.Builder; using Microsoft.AspNetCore.Hosting.Internal; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Startup; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; 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; // Only one of these should be set private StartupMethods _startup; private Type _startupType; // Only one of these should be set private IServerFactory _serverFactory; /// /// Initializes a new instance of the class. /// public WebHostBuilder() { _hostingEnvironment = new HostingEnvironment(); _configureServicesDelegates = new List>(); _configureLoggingDelegates = new List>(); } /// /// 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; } /// /// Specify the to be used by the web host. /// /// The to be used. /// The . public IWebHostBuilder UseServer(IServerFactory factory) { if (factory == null) { throw new ArgumentNullException(nameof(factory)); } _serverFactory = factory; return this; } /// /// Specify the startup type to be used by the web host. /// /// The to be used. /// The . public IWebHostBuilder UseStartup(Type startupType) { if (startupType == null) { throw new ArgumentNullException(nameof(startupType)); } _startupType = startupType; 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; } /// /// Specify the startup method to be used to configure the web application. /// /// The delegate that configures the . /// The . public IWebHostBuilder Configure(Action configureApp) { if (configureApp == null) { throw new ArgumentNullException(nameof(configureApp)); } _startup = new StartupMethods(configureApp); 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 appEnvironment = hostingContainer.GetRequiredService(); var startupLoader = hostingContainer.GetRequiredService(); var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, appEnvironment.ApplicationBasePath); var applicationName = ResolveApplicationName() ?? appEnvironment.ApplicationName; // Initialize the hosting environment _hostingEnvironment.Initialize(applicationName, contentRootPath, _options); var host = new WebHost(hostingServices, startupLoader, _options, _config); // Only one of these should be set, but they are used in priority host.ServerFactory = _serverFactory; host.ServerFactoryLocation = _options.ServerFactoryLocation; // Only one of these should be set, but they are used in priority host.Startup = _startup; host.StartupType = _startupType; host.StartupAssemblyName = _options.Application; host.Initialize(); return host; } private IServiceCollection BuildHostingServices() { _options = new WebHostOptions(_config); 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.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(); var defaultPlatformServices = PlatformServices.Default; services.AddSingleton(defaultPlatformServices.Application); services.AddSingleton(defaultPlatformServices.Runtime); 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); } private string ResolveApplicationName() { if (_startup != null) { return _startup.ConfigureDelegate.Target.GetType().GetTypeInfo().Assembly.GetName().Name; } if (_startupType != null) { return _startupType.GetTypeInfo().Assembly.GetName().Name; } if (!string.IsNullOrEmpty(_options.Application)) { return _options.Application; } return null; } } }