// 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);
}
}
}