File: StartupHook.cs
Web Access
Project: src\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 Microsoft.AspNetCore.Hosting.Views;
using Microsoft.AspNetCore.Server.IIS;
using Microsoft.Extensions.FileProviders;
 
/// <summary>
/// Startup hooks are pieces of code that will run before a users program main executes
/// See: <see href="https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/host-startup-hook.md"/>
/// The type must be named StartupHook without any namespace, and should be internal.
/// </summary>
internal sealed class StartupHook
{
    /// <summary>
    /// Startup hooks are pieces of code that will run before a users program main executes
    /// See: <see href="https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/host-startup-hook.md"/>
    /// </summary>
    public static void Initialize()
    {
        if (!NativeMethods.IsAspNetCoreModuleLoaded())
        {
            // This means someone set the startup hook for Microsoft.AspNetCore.Server.IIS
            // but are not running inprocess. Return at this point.
            return;
        }
 
        var detailedErrors = Environment.GetEnvironmentVariable("ASPNETCORE_DETAILEDERRORS");
        var enableStartupErrorPage = detailedErrors?.Equals("1", StringComparison.OrdinalIgnoreCase) ?? false;
        enableStartupErrorPage |= detailedErrors?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
 
        var aspnetCoreEnvironment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        enableStartupErrorPage |= aspnetCoreEnvironment?.Equals("Development", StringComparison.OrdinalIgnoreCase) ?? false;
 
        var dotnetEnvironment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");
        enableStartupErrorPage |= dotnetEnvironment?.Equals("Development", StringComparison.OrdinalIgnoreCase) ?? false;
 
        if (!enableStartupErrorPage)
        {
            // Not running in development or detailed errors aren't enabled
            return;
        }
 
        AppDomain.CurrentDomain.UnhandledException += (sender, eventArgs) =>
        {
            var exception = (Exception)eventArgs.ExceptionObject;
 
            // Get the content root from IIS.
            var iisConfigData = NativeMethods.HttpGetApplicationProperties();
            var contentRoot = iisConfigData.pwzFullApplicationPath.TrimEnd(Path.DirectorySeparatorChar);
 
            var model = ErrorPageModelBuilder.CreateErrorPageModel(
                new PhysicalFileProvider(contentRoot),
                logger: null,
                showDetailedErrors: true,
                exception);
 
            var errorPage = new ErrorPage(model);
 
            var stream = new MemoryStream();
 
            // Never will go async because we are writing to a memory stream.
            errorPage.ExecuteAsync(stream).GetAwaiter().GetResult();
 
            // Get the raw content and set the error page.
            stream.Position = 0;
            var content = stream.ToArray();
 
            NativeMethods.HttpSetStartupErrorPageContent(content);
        };
    }
}