| File: WebHostBuilderIISExtensions.cs | Web Access |
| Project: src\aspnetcore\src\Servers\IIS\IIS\src\Microsoft.AspNetCore.Server.IIS.csproj (Microsoft.AspNetCore.Server.IIS) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Connections; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Server.IIS; using Microsoft.AspNetCore.Server.IIS.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; namespace Microsoft.AspNetCore.Hosting; /// <summary> /// Extension methods for the IIS In-Process. /// </summary> public static class WebHostBuilderIISExtensions { /// <summary> /// Configures the port and base path the server should listen on when running behind AspNetCoreModule. /// The app will also be configured to capture startup errors. /// </summary> /// <param name="hostBuilder">The <see cref="IWebHostBuilder"/> to configure.</param> /// <returns>The <see cref="IWebHostBuilder"/>.</returns> public static IWebHostBuilder UseIIS(this IWebHostBuilder hostBuilder) { ArgumentNullException.ThrowIfNull(hostBuilder); // Check if in process if (OperatingSystem.IsWindows() && NativeMethods.IsAspNetCoreModuleLoaded()) { var iisConfigData = NativeMethods.HttpGetApplicationProperties(); // Trim trailing slash to be consistent with other servers var contentRoot = iisConfigData.pwzFullApplicationPath.TrimEnd(Path.DirectorySeparatorChar); hostBuilder.UseContentRoot(contentRoot); return hostBuilder.ConfigureServices( services => { services.AddSingleton(new IISNativeApplication(new NativeSafeHandle(iisConfigData.pNativeApplication))); services.AddSingleton<IServer, IISHttpServer>(); services.AddTransient<IISServerAuthenticationHandlerInternal>(); services.AddSingleton<IStartupFilter, IISServerSetupFilter>(); services.AddAuthenticationCore(); services.AddSingleton<IServerIntegratedAuth>(_ => new ServerIntegratedAuth() { IsEnabled = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled, AuthenticationScheme = IISServerDefaults.AuthenticationScheme }); services.Configure<IISServerOptions>( options => { options.ServerAddresses = iisConfigData.pwzBindings.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); options.ForwardWindowsAuthentication = iisConfigData.fWindowsAuthEnabled || iisConfigData.fBasicAuthEnabled; options.MaxRequestBodySize = iisConfigData.maxRequestBodySize; options.IisMaxRequestSizeLimit = iisConfigData.maxRequestBodySize; } ); services.TryAddSingleton<IMemoryPoolFactory<byte>, DefaultMemoryPoolFactory>(); services.TryAddSingleton<MemoryPoolMetrics>(); // Replace default ConsoleLifetime as it can cause shutdown hangs with Preload Enabled = true services.AddSingleton<IHostLifetime, IISHostLifetime>(); }); } return hostBuilder; } private sealed class IISHostLifetime : IHostLifetime, IDisposable { private readonly IHostApplicationLifetime _applicationLifetime; private PosixSignalRegistration? _sigTermRegistration; public IISHostLifetime(IHostApplicationLifetime applicationLifetime) { _applicationLifetime = applicationLifetime; } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task WaitForStartAsync(CancellationToken cancellationToken) { _sigTermRegistration = PosixSignalRegistration.Create(PosixSignal.SIGTERM, _ => { // Logic copied from // https://github.com/dotnet/runtime/blob/535c5deba263df5bd4be244247e43bddce288254/src/libraries/Microsoft.Extensions.Hosting/src/Internal/ConsoleLifetime.netcoreapp.cs#L38 // don't allow Dispose to unregister handlers, since Windows has a lock that prevents the unregistration while this handler is running // just leak these, since the process is exiting _sigTermRegistration = null; _applicationLifetime.StopApplication(); // Equivalent to the pre-10.0 version of ConsoleLifetime // Does not copy Thread.Sleep(HostOptions.ShutdownTimeout) // from ConsoleLifetime because that causes machine shutdown to hang // if Preload Enabled = true // Likely an IIS/WAS issue. }); return Task.CompletedTask; } public void Dispose() { _sigTermRegistration?.Dispose(); } } }