Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

app_offline.htm throwing HTTP 500 errors on production box

I have created an app_offline.htm file for an ASP.NET MVC2 application running on IIS7 / Win2008 64-bit, and ensured that it's over 512 bytes (it's 2KB right now). On my dev box running Visual Studio 2010, it works like a charm, but when I put it on the production box, all I get is the generic HTTP 500 error saying "The page cannot be displayed because an internal server error has occurred."

What's especially strange is that I don't get anything logged in the application event log, nor does ELMAH pick anything up. I've disabled custom errors, put FormsAuthentication location exceptions for the file, ensured I'm not referencing any other files (images, etc.), but nothing fixes it.

I've read every post on SO and Googled for hours and can't figure this out. Any ideas what might be wrong? I'm pulling my hair out here...

like image 789
Josh Anderson Avatar asked Feb 08 '11 00:02

Josh Anderson


2 Answers

UPDATE:
Do you have this in your web.config?

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.web>
        <httpRuntime waitChangeNotification="300" maxWaitChangeNotification="300"/>
    </system.web>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
</configuration>

But there’s one more catch.

ASP.NET will unload the application as soon as the web.config is changed, but it won’t actually reload it and apply the “waitChange…” settings until a request is made. So you could still drop the app_offline.htm and web.config in, and if the first requst occurs while a dll is only half copied, the exception will occur. To add insult to injury, the exception will persist until you replace the temporary web.config or the total duration of your “waitChange…” time expires!

To get around this final hurdle, you’d need to make a request to the application after uploading the temporary web.config, but before you start deploying the application files. The complete process is as follows:

  1. Add app_offline.htm
  2. Replace application’s web.config with a temporary web.config (as above)
  3. Request any ASP.NET resource on the site so the new waitChangeNotification gets “applied”*
  4. Make any file system changes necessary (deploy bin dlls, other site files)
  5. Replace temporary web.config with the original application web.config
  6. Delete app_offline.htm

*You may dispute what happens in step 2-3, since ASP.NET shuts down the application after step 1. Indeed, it does not appear from my event viewer that the web.config change is registered or “applied” as a result of either step 2 or 3, but nevertheless the updated waitChangeNotification settings do get applied after step 3.

More app_offline.htm woes

App_offline.htm gotchas with ASP.NET MVC

like image 88
rick schott Avatar answered Nov 16 '22 01:11

rick schott


I came up with a solution that works 100% for our deploys, so I thought I'd share it.

This solution adds a customErrors section to the web.config. This will catch any unhandled exceptions. It redirects to the App_Offline.htm, which refreshes until the application comes back online. So the user gets a nice loader that goes away when the application becomes available.

I hope this is helpful :)

Batch File

copy "C:\www\_App_Offline.htm" "C:\www\App_Offline.htm"
copy /y "C:\www\App_Offline.config" "C:\www\Web.config"

Rem do deploy/publish actions

Rem Note: Our publish replaces/restores the Web.config. You should do that here.
del "C:\www\App_Offline.htm"

App_Offline.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <httpRuntime waitChangeNotification="100" maxWaitChangeNotification="100"/>
    <customErrors defaultRedirect="App_Offline.htm" mode="On">
    </customErrors>
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
</configuration>

_App_Offline.htm

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Application Offline</title>
    <meta charset="UTF-8">
    <style>
        .facebook_blockG { background-color: none; border: 3px solid #D6D6D6; float: left; height: 40px; margin-left: 7px; width: 24px; opacity: 0; -moz-animation-name: bounceG; -moz-animation-duration: 1.3s; -moz-animation-iteration-count: infinite; -moz-animation-direction: linear; -moz-transform: scale(0.7); -webkit-animation-name: bounceG; -webkit-animation-duration: 1.3s; -webkit-animation-iteration-count: infinite; -webkit-animation-direction: linear; -webkit-transform: scale(0.7); -ms-animation-name: bounceG; -ms-animation-duration: 1.3s; -ms-animation-iteration-count: infinite; -ms-animation-direction: linear; -ms-transform: scale(0.7); -o-animation-name: bounceG; -o-animation-duration: 1.3s; -o-animation-iteration-count: infinite; -o-animation-direction: linear; -o-transform: scale(0.7); animation-name: bounceG; animation-duration: 1.3s; animation-iteration-count: infinite; animation-direction: linear; transform: scale(0.7); }
        #blockG_1 { -moz-animation-delay: 0.39s; -webkit-animation-delay: 0.39s; -ms-animation-delay: 0.39s; -o-animation-delay: 0.39s; animation-delay: 0.39s; }
        #blockG_2 { -moz-animation-delay: 0.52s; -webkit-animation-delay: 0.52s; -ms-animation-delay: 0.52s; -o-animation-delay: 0.52s; animation-delay: 0.52s; }
        #blockG_3 { -moz-animation-delay: 0.65s; -webkit-animation-delay: 0.65s; -ms-animation-delay: 0.65s; -o-animation-delay: 0.65s; animation-delay: 0.65s; }

        @-moz-keyframes bounceG {
            0% { -moz-transform: scale(1.2); opacity: 0.6; }

            100% { -moz-transform: scale(0.7); opacity: 0; }
        }

        @-webkit-keyframes bounceG {
            0% { -webkit-transform: scale(1.2); opacity: 0.6; }

            100% { -webkit-transform: scale(0.7); opacity: 0; }
        }

        @-ms-keyframes bounceG {
            0% { -ms-transform: scale(1.2); opacity: 0.6; }

            100% { -ms-transform: scale(0.7); opacity: 0; }
        }

        @-o-keyframes bounceG {
            0% { -o-transform: scale(1.2); opacity: 0.6; }

            100% { -o-transform: scale(0.7); opacity: 0; }
        }

        @keyframes bounceG {
            0% { transform: scale(1.2); opacity: 0.6; }

            100% { transform: scale(0.7); opacity: 0; }
        }
    </style>
</head>
<body>

    <div id="overlay" class="trans">
        <div id="overlay-inner" class="trans login">
            <h1 style="line-height:1em; font-size:30pt">Application Offline</h1>
            <h2 style="line-height:1em; width:70%; margin:auto">application is offline for maintenance</h2>
            <div style="width: 128px; margin:40px auto">
                <div id="blockG_1" class="facebook_blockG">
                </div>
                <div id="blockG_2" class="facebook_blockG">
                </div>
                <div id="blockG_3" class="facebook_blockG">
                </div>
            </div>
        </div>
    </div>

    <script type="text/javascript">
        function getParameterByName(name) {
            name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
            var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
                results = regex.exec(location.search);
            return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
        }
        setTimeout(function () {
            var loc = getParameterByName('aspxerrorpath');
            loc = (loc) ? window.location.protocol + '//' + window.location.host + loc : window.location.href;
            window.location.assign(loc);
        }, 1500);
    </script>
</body>
</html>
like image 40
N-ate Avatar answered Nov 16 '22 00:11

N-ate