ASP.NET Core 3.1 InProcess 托管应用程序在启动异常后未重新启动

Com*_*eak 5 c# asp.net iis .net-core

问题

我有一个使用 IIS 托管的 InProcess ASP.NET Core Web 应用程序。我实现了每次启动时抛出的异常。正如预期的那样,IIS 显示此错误页面:

HTTP 错误 500.30 - ANCM 进程内启动失败

此问题的常见解决方案:

  • 应用程序无法启动
  • 应用程序启动但随后停止
  • 应用程序启动但在启动过程中抛出异常

故障排除步骤:

  • 检查系统事件日志以获取错误消息
  • 启用记录应用程序进程的标准输出消息
  • 将调试器附加到应用程序进程并检查

有关更多信息,请访问:https : //go.microsoft.com/fwlink/?LinkID=2028265

在 .Net Core 2.2(带有CaptureStartupErrors(false))以及经典的 ASP.NET 应用程序中,IIS 尝试在下一个请求时再次启动应用程序。

对于 .Net Core 3.1,它不会尝试重新启动,它只会永远保持这种状态,无论我为CaptureStartupErrors.

解决方法

我可以通过捕获异常并退出来解决此问题 - 如果我这样做,它将按预期运行:

public static void Main(string[] args)
{
    try
    {
        CreateWebHostBuilder(args).Build().Run();
    }
    catch (Exception)
    {
        Environment.Exit(-1);
    }
}
Run Code Online (Sandbox Code Playgroud)

预期行为

对于如何更改此行为的任何想法,我都很高兴,因此在不使用此解决方法的情况下,它的行为与以前相同。如果我的应用程序抛出一个未处理的异常,它应该退出并尝试在下一个请求时重新启动。

我试过的

  • 使用不同的值 CaptureStartupErrors
  • 查找更改此行为的配置参数
  • 在“发布”-配置而不是“调试”中发布
  • 在 Github 上创建了一个问题

重现问题的代码

Github 上的存储库

当您将应用程序发布到 IIS 时会出现此问题,并且在没有 IIS 的情况下无法重现。

程序.cs:

public class Program
{
    public static void Main(string[] args)
    {
        File.AppendAllText("log.txt", $"{DateTime.Now.ToLongTimeString()}:Starting\r\n");
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateWebHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder( args )
            .ConfigureWebHostDefaults( webBuilder =>
            {
                webBuilder
                    .UseStartup<Startup>();
            } );
}
Run Code Online (Sandbox Code Playgroud)

启动.cs:

public class Startup
{
    public Startup( IConfiguration configuration )
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices( IServiceCollection services )
    {

    }

    public void Configure( IApplicationBuilder app, IHostingEnvironment env )
    {
        throw new Exception();

    }
}
Run Code Online (Sandbox Code Playgroud)

以下文件大多是默认的,但如果你想检查

网络配置:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet" arguments=".\WebApplication20.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
    </system.webServer>
  </location>
</configuration>
Run Code Online (Sandbox Code Playgroud)

.csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
  </ItemGroup>

</Project>
Run Code Online (Sandbox Code Playgroud)

FolderProfile.pubxml:

<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <DeleteExistingFiles>False</DeleteExistingFiles>
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
    <LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <PublishProvider>FileSystem</PublishProvider>
    <PublishUrl>C:\inetpub\wwwroot\test</PublishUrl>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <SiteUrlToLaunchAfterPublish />
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <ProjectGuid>9ec27b57-5f45-4286-aa7c-12abad61a153</ProjectGuid>
    <SelfContained>false</SelfContained>
  </PropertyGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)

Com*_*eak 3

正如微软在我的问题中解释的那样,这是预期的行为:

我相信这种行为是预期的,并且是 IIS 进程外和进程内之间的行为差​​异。然而,我们可以考虑尝试改变进程内的行为。

在 2.2 中,听起来您在进程外使用 IIS,正如您所说,您在完整框架中看到了这种行为。如果 dotnet 进程崩溃,ANCM 将不断尝试重新启动它。

但是,在 3.1/in-process 中,如果应用程序在启动时崩溃,ANCM 将不会重新启动该进程。这是出于以下几个原因:

因为我们是在进程内运行,所以我们需要完全重新启动 w3wp.exe/iisexpress.exe 进程,因为我们不能两次启动 dotnet 运行时而不可能出现不良行为。不断地重新启动 w3wp 进程通常不是一个好主意。我们假设,如果进程在启动时抛出未处理的异常,我们应该要求在重试之前重新部署应用程序。这在当时可能不是正确的决定,但却是行为改变的关键原因。

因此,我的问题的解决方案是使用解决方法或以其他方式处理异常。如果您决定使用解决方法,您应该知道 IIS 具有可配置的快速故障保护功能 ,如果应用程序池重新启动过于频繁,则会停止应用程序池。

AFAIK,您必须调用 Environment.Exit(-1) 的代码可能会工作几次,但我相信调用几次后,IIS 将触发快速故障保护,这将迫使站点不再启动。