The truth about app_offline.htm


In this short post I would like to present you am interesting fact about app_offline.htm. Let’s start with a small puzzle. Imagine you have 2 files in your IIS application folder: web.config and app_offline.htm. Web.config contains following lines:

<?xml version="1.0"?>
<configuration>
</configuration

and app_offline.htm:

We'll be back in a moment.

Notice that in the web.config file the configuration tag is not closed. Now the question is: what will you see if you try to access your application from the browser?

I was a bit surprised when I saw HTTP Error 500.19 – Internal Server Error:

500.19 - Internal Server Error

instead of the content of my app_offline.htm file. From the image we can also see that it’s IIS Web Core that generates this error. To understand what happened I needed to find a method in ASP.NET framework that renders this special file. It didn’t take long till I stumbled upon a CheckApplicationEnabled method in the System.Web.HttpRuntime class (decompiled with dotPeek):

internal static void CheckApplicationEnabled()
{
  string str = Path.Combine(HttpRuntime._theRuntime._appDomainAppPath, &quot;App_Offline.htm&quot;);
  bool flag = false;
  HttpRuntime._theRuntime._fcm.StartMonitoringFile(str, new FileChangeEventHandler(HttpRuntime._theRuntime.OnAppOfflineFileChange));
  try
  {
    if (System.IO.File.Exists(str))
    {
      using (FileStream fileStream = new FileStream(str, FileMode.Open, FileAccess.Read, FileShare.Read))
      {
        if (fileStream.Length <= 1048576L)         {           
          int count = (int) fileStream.Length;
          if (count > 0)
          {
            byte[] buffer = new byte[count];
            if (fileStream.Read(buffer, 0, count) == count)
            {
              HttpRuntime._theRuntime._appOfflineMessage = buffer;
              flag = true;
            }
          }
          else
          {
            flag = true;
            HttpRuntime._theRuntime._appOfflineMessage = new byte[0];
          }
        }
      }
    }
  }
  catch
  {
  }
  if (flag)
    throw new HttpException(503, string.Empty);
  if (!RuntimeConfig.GetAppConfig().HttpRuntime.Enable)
    throw new HttpException(404, string.Empty);
}

This method is called either on HttpRuntime initialization or when a special application pool is created.

To summarize, it’s HttpRuntime that generates 503 response code and renders a friendly error message. So if anything happens while HttpRuntime is initializing (missing dlls, invalid configuration file etc.) you won’t see this message but less friendly 500 Internal Error. With IIS 7 and above IIS Web Core module will stop request execution even before it reaches the managed runtime.

One thought on “The truth about app_offline.htm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s