| File: GenericHost\GenericWebHostService.cs | Web Access |
| Project: src\aspnetcore\src\Hosting\Hosting\src\Microsoft.AspNetCore.Hosting.csproj (Microsoft.AspNetCore.Hosting) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Linq; using Microsoft.AspNetCore.Hosting.Builder; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Hosting; internal sealed partial class GenericWebHostService : IHostedService { public GenericWebHostService(IOptions<GenericWebHostServiceOptions> options, IServer server, ILoggerFactory loggerFactory, DiagnosticListener diagnosticListener, ActivitySource activitySource, DistributedContextPropagator propagator, IHttpContextFactory httpContextFactory, IApplicationBuilderFactory applicationBuilderFactory, IEnumerable<IStartupFilter> startupFilters, IConfiguration configuration, IWebHostEnvironment hostingEnvironment, HostingMetrics hostingMetrics) { Options = options.Value; Server = server; Logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Hosting.Diagnostics"); LifetimeLogger = loggerFactory.CreateLogger("Microsoft.Hosting.Lifetime"); DiagnosticListener = diagnosticListener; ActivitySource = activitySource; Propagator = propagator; HttpContextFactory = httpContextFactory; ApplicationBuilderFactory = applicationBuilderFactory; StartupFilters = startupFilters; Configuration = configuration; HostingEnvironment = hostingEnvironment; HostingMetrics = hostingMetrics; } public GenericWebHostServiceOptions Options { get; } public IServer Server { get; } public ILogger Logger { get; } // Only for high level lifetime events public ILogger LifetimeLogger { get; } public DiagnosticListener DiagnosticListener { get; } public ActivitySource ActivitySource { get; } public DistributedContextPropagator Propagator { get; } public IHttpContextFactory HttpContextFactory { get; } public IApplicationBuilderFactory ApplicationBuilderFactory { get; } public IEnumerable<IStartupFilter> StartupFilters { get; } public IConfiguration Configuration { get; } public IWebHostEnvironment HostingEnvironment { get; } public HostingMetrics HostingMetrics { get; } public async Task StartAsync(CancellationToken cancellationToken) { HostingEventSource.Log.HostStart(); var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>(); var addresses = serverAddressesFeature?.Addresses; if (addresses != null && !addresses.IsReadOnly && addresses.Count == 0) { // We support reading "urls" from app configuration var urls = Configuration[WebHostDefaults.ServerUrlsKey]; // But fall back to host settings if (string.IsNullOrEmpty(urls)) { urls = Options.WebHostOptions.ServerUrls; } var httpPorts = Configuration[WebHostDefaults.HttpPortsKey] ?? string.Empty; var httpsPorts = Configuration[WebHostDefaults.HttpsPortsKey] ?? string.Empty; if (string.IsNullOrEmpty(urls)) { // HTTP_PORTS and HTTPS_PORTS, these are lower priority than Urls. static string ExpandPorts(string ports, string scheme) { return string.Join(';', ports.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) .Select(port => $"{scheme}://*:{port}")); } var httpUrls = ExpandPorts(httpPorts, Uri.UriSchemeHttp); var httpsUrls = ExpandPorts(httpsPorts, Uri.UriSchemeHttps); urls = $"{httpUrls};{httpsUrls}"; } else if (!string.IsNullOrEmpty(httpPorts) || !string.IsNullOrEmpty(httpsPorts)) { Logger.PortsOverridenByUrls(httpPorts, httpsPorts, urls); } if (!string.IsNullOrEmpty(urls)) { // We support reading "preferHostingUrls" from app configuration var preferHostingUrlsConfig = Configuration[WebHostDefaults.PreferHostingUrlsKey]; // But fall back to host settings if (!string.IsNullOrEmpty(preferHostingUrlsConfig)) { serverAddressesFeature!.PreferHostingUrls = WebHostUtilities.ParseBool(preferHostingUrlsConfig); } else { serverAddressesFeature!.PreferHostingUrls = Options.WebHostOptions.PreferHostingUrls; } foreach (var value in urls.Split(';', StringSplitOptions.RemoveEmptyEntries)) { addresses.Add(value); } } } RequestDelegate? application = null; try { var configure = Options.ConfigureApplication; if (configure == null) { throw new InvalidOperationException($"No application configured. Please specify an application via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration."); } var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features); foreach (var filter in Enumerable.Reverse(StartupFilters)) { configure = filter.Configure(configure); } configure(builder); // Build the request pipeline application = builder.Build(); } catch (Exception ex) { Logger.ApplicationError(ex); if (!Options.WebHostOptions.CaptureStartupErrors) { throw; } var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors; application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex); } var httpApplication = new HostingApplication(application, Logger, DiagnosticListener, ActivitySource, Propagator, HttpContextFactory, HostingEventSource.Log, HostingMetrics); await Server.StartAsync(httpApplication, cancellationToken); HostingEventSource.Log.ServerReady(); if (addresses != null) { foreach (var address in addresses) { Log.ListeningOnAddress(LifetimeLogger, address); if (LifetimeLogger.IsEnabled(LogLevel.Information)) { if (address.Contains(".localhost", StringComparison.OrdinalIgnoreCase) && Uri.TryCreate(address, UriKind.Absolute, out var uri) && uri.Host.EndsWith(".localhost", StringComparison.OrdinalIgnoreCase)) { // Log the localhost address without the sub-domain prefix too Log.ListeningOnAddress(LifetimeLogger, new UriBuilder(uri) { Host = "localhost" }.ToString().TrimEnd('/')); } } } } if (Logger.IsEnabled(LogLevel.Debug)) { foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies()) { Log.StartupAssemblyLoaded(Logger, assembly); } } if (Options.HostingStartupExceptions != null) { foreach (var exception in Options.HostingStartupExceptions.InnerExceptions) { Logger.HostingStartupAssemblyError(exception); } } } public async Task StopAsync(CancellationToken cancellationToken) { try { await Server.StopAsync(cancellationToken); } finally { HostingEventSource.Log.HostStop(); } } private static partial class Log { [LoggerMessage(14, LogLevel.Information, "Now listening on: {address}", EventName = "ListeningOnAddress")] public static partial void ListeningOnAddress(ILogger logger, string address); [LoggerMessage(13, LogLevel.Debug, "Loaded hosting startup assembly {assemblyName}", EventName = "HostingStartupAssemblyLoaded", SkipEnabledCheck = true)] public static partial void StartupAssemblyLoaded(ILogger logger, string assemblyName); } }