5
votes

The issue

I've got an ASP.NET Core Web-Application hosted InProcess using IIS. I implemented an exception thrown at every startup. As expected, IIS shows this error page:

HTTP Error 500.30 - ANCM In-Process Start Failure

Common solutions to this issue:

  • The application failed to start
  • The application started but then stopped
  • The application started but threw an exception during startup

Troubleshooting steps:

  • Check the system event log for error messages
  • Enable logging the application process' stdout messages
  • Attach a debugger to the application process and inspect

For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028265

In .Net Core 2.2 (with CaptureStartupErrors(false)) as well as for classic ASP.NET-Applications the IIS tries to start the app again on the next request.

For .Net Core 3.1 it does not attempt to restart, it just stays in this state forever, no matter what I set for CaptureStartupErrors.

Workaround

I can workaround this by catching the exception and exiting - it will behave as expected if I do this:

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

Expected behaviour

I'd be happy for any ideas how to change this behavior so it does behave the same as before without using this workaround. If my application throws an unhandled exception, it should exit and attempt to restart on the next request.

What I've tried

  • Using different values for CaptureStartupErrors
  • Finding configuration parameters that change this behavior
  • Publishing in "Release"-Configuration instead of "Debug"
  • Created an issue on Github

Code to reproduce the issue

Repository on Github

The issue occures when you publish the application to an IIS and is not reproducible without IIS.

Program.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>();
            } );
}

Startup.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();

    }
}

The following files are mostly default, but if you want to check:

web.config:

<?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>

.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>

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>
2
What error is it that crashes the application, is that error solvable?mortb
It's more of a general question, but I come from a SocketFailure (ReadSocketError/ConnectionReset occuring randomly after a system reboot while connecting to our Redis-Server as some part of the system does not seem to be fully initialised at this moment. Implementing a retry would be an option, but we would prefer to use the native functionality of the IIS to wrap the complete application and handle all future incidents instead of implementing a specific solution for this single case of the issue.Compufreak
@Compufreak i have simillar feeling about this issue i even wrote comment on github github.com/dotnet/aspnetcore/issues/…RedgoodBreaker

2 Answers

2
votes

As Microsoft did explain in my issue this is intended behavior:

I believe this behavior is expected and is a behavior difference between IIS Out-of-process and In-Process. However, we could consider trying to change the behavior for in-process.

In 2.2, it sounds like you were using IIS out-of-process, as you said you saw this behavior with Full Framework. ANCM will constantly try to restart the dotnet process if it crashes.

However, in 3.1/in-process, if the application crashes on Startup, ANCM will not restart the process if it crashes on Startup. This is for a few reasons:

Because we are running in-process, we need to restart the w3wp.exe/iisexpress.exe process entirely as we can't start the dotnet runtime twice without possibility for bad behavior. Constantly restarting the w3wp process is usually not a good idea. We made an assumption that if a process throws an unhandled exception on startup, we should required the app to be redeployed before trying again. This may not have been the right decision at the time, but it is a key reason for the behavior change.

Thus the solution for my issue is to either use the workaround or to handle the exception in another way. If you decide to use the workaround you should be aware that IIS has a configurable rapid failure protection stopping the application pool if it restarts too often.

AFAIK, the code you have to call Environment.Exit(-1) may work for a few tries, however I believe that after calling that a few times, IIS will trigger Rapid Failure protection which will force the site not to start again.

0
votes

Try to verify the versions like target framework is 3.+ or 3 then one more check is sdk runtime for 3.+

Properties need to be verified:- netcoreapp3.1 --> InProcess

This works fine after having all this and i just restarted my system and open the solution to run it.

Try and let me know if still it doesn't work