Getting ASP.NET Core Applications Production Ready in Elastic Beanstalk (IIS 10)

By default, there are several settings in IIS which would cause issues in Production for high-load applications.

(Steps below were tested on Win 2016, IIS 10, running ASP.NET Core 2.0.1 with .NET Framework 4.7.1)

Firstly, IIS is configured to shut down a process after x minutes of inactivity. The default setting is 20 minutes. The setting is called “Idle Time-Out (mintues)”.

In a web farm scenario, for one reason or another, you can have a node that did not receive a request in a span of 20 minutes. Once the node does receive the request, it will have to spin up the ASP.NET Core app, which takes some time. The user will then have to wait for the spin up to complete before receiving the response. This results in sub-ideal user experience.

To disable the timeout run this command:

(You can add these commands as .configs in your .ebextensions)

%systemroot%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools /applicationPoolDefaults.processModel.idleTimeout:00:00:00 /commit:apphost

Also, IIS will recycle an app pool after very 29 hours (1740 minutes). To disable the auto-recycle, run this command:

%systemroot%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools /applicationPoolDefaults.recycling.periodicRestart.time:00:00:00 /commit:apphost

Then, we need to set the start mode to “AlwaysRunning” instead of the default “OnDemand”

%systemroot%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools /applicationPoolDefaults.autoStart:"True" /commit:apphost

%systemroot%\system32\inetsrv\appcmd.exe set config -section:system.applicationHost/applicationPools /applicationPoolDefaults.startMode:"AlwaysRunning" /commit:apphost

When deploying a new version of the app, IIS or ElasticBeanstalk will NOT automatically warm up or invoke your application. For this to happen you need to either automatically call each EC2 node and warm it up, or you can use IIS Application Initialization (https://docs.microsoft.com/en-us/iis/configuration/system.webserver/applicationinitialization/)

By default, EC2 nodes do not have this feature enabled. To enable the feature, install it via:

powershell.exe -Command "Install-WindowsFeature Web-AppInit"

Then, in you web.config, specify the path which should be called to warm up the application. In this example, warmup action is called on the Home controller.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
   <system.webServer>
     <applicationInitialization>
       <add initializationPage="home/warmup" />
     </applicationInitialization>
   </system.webServer>
</configuration>

And here’s the controller/method:

public class HomeController : Controller
{
    [HttpGet]
    public async Task Warmup()
    {
        // do warmup
        // kick out requests not coming from 127.0.0.1 or ::1
    }
}

In the warmup method (action), I strongly recommend you check if the request is coming from ::1 or 127.0.0.1, and if it is not, disallow the warmup. This will prevent from someone doing a warmup (which is often expensive) without having the authorization to do so. Since the IIS Application Initialization module is doing the invocation of your warmup method, the request will come from 127.0.0.1

Lastly, you need to set “Preload Enabled” to “True” for all your sites via this command:

%systemroot%\system32\inetsrv\AppCmd.exe list app /xml | %windir%\system32\inetsrv\appcmd set app /in /preloadEnabled:True

And there you have it, your ASP.NET Core applications are now production ready!