App_offline.htm gotchas with ASP.NET MVC

July 12, 2010

You could be inadvertently exposing your visitors to unfriendly 404 and 403 errors when updating your ASP.NET MVC application, even after deploying an app_offline.htm file!

How app_offline.htm is supposed to work

The ability to take an ASP.NET application temporarily offline by uploading a file named app_offline.htm was a little known, undocumented feature of ASP.NET 2.0 until popularized by Scott Gu’s post about it back in 2005. How it works is simple, to quote Scott:

[If you place a file named app_offline.htm] in the root of a web application directory, ASP.NET 2.0 will shut-down the application, unload the application domain from the server, and stop processing any new incoming requests for that application. ASP.NET will also then respond to all requests for dynamic pages in the application by sending back the content of the app_offline.htm file (for example: you might want to have a “site under construction” or “down for maintenance” message).

Interestingly, this is the second most popular “hidden feature of ASP.NET” on Stack Overflow.

This technique works for traditional ASP.NET 2.0 web forms because typically every url on a site corresponds to an .aspx file. The application gets unloaded and the request for such a dynamic page results in the serving of a friendly “down for maintenance” type of message to any visitor accessing virtually any page of the site.

Try this with an ASP.NET MVC application though, and consider the potential horror:

403 - Forbidden

404 - File not found

(Note the 403 error occurs on the application root (“blog” in this case) and the 404 occurs on any MVC Controller Action “page.”)

Why this happens with ASP.NET MVC

Don’t believe me? Go ahead and drop an app_offline.htm file into your application root and… wait… what errors? Everything appears to be working as expected…

project directory site offline

Everything seems fine.

I’ll get to this in just a minute, but let’s consider a different scenario where we’re doing a major deployment and perhaps deleting everything including the web.config in the application’s directory first, leaving us with just a lonely app_offline.htm file. The result, alas:

empty directory with app_offline.htm  404 - file not found

What gives?

Let’s consider the latter scenario where we have an app_offline.htm file and nothing else in our application directory. Though this tells IIS to unload the application and serve up this file in place of dynamic resources such as .aspx pages, it doesn’t change the way it handles other resource requests, and without certain configurations in IIS and/or a web.config file (when present) your visitors may still see 404 or 403 errors.

403 – Forbidden: Access is denied.

If you don’t have “app_offline.htm” listed in the IIS Default Document configuration (and you have directory browsing turned off) you’ll get a 403 error when trying to access the root of a site. IIS simply tries to find the first match for a default document to serve up, and if it doesn’t find one it will return the 403.

You could simply add “app_offline.htm” to the defaut document configuration to get around this error. IIS will find it, and serve up your friendly offline page. Alternatively you could add any .aspx page (such as default.aspx – an empty file is fine) that is configured as a possible default document. This will clue IIS in that an ASP.NET resource is being requested and cause it to serve up the app_offline.htm instead.

404 – File or directory not found.

When you request a dynamic “MVC resource,” such as a Controller Action method with its inherent friendly url (eg. http://kurtschindler.net/blog/post/some-post-here) you’ll get a 404. Think about the consequences here. Even if your application root was showing a friendly “down for maintenance” page, many other potential visitors may be accessing other pages directly and being fooled into thinking they no longer exist!

Again, IIS knows not, and assumes you are requesting a default document in a directory that matches the url specified (eg. it’s looking for a default document under [root]\blog\post\some-post-here). Of course, no such directory or document exists. 404.

In both scenarios, IIS has no clue ASP.NET is involved and thus completely ignores the presence of the app_offline.htm file. So the solution is to tell IIS to runAllManagedModulesForAllRequests so it invokes ASP.NET which then serves up the app_offline.htm page.

The web.config solution

Add a web.config along with your app_offline.htm with just the bare minimum required setting:

<?xml version="1.0"?>
<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
</configuration>

Now request any resource on your site again and the app_offline.htm takes over as expected!

empty dir with app_offline and web.config site offline

This web.config is required to tell IIS to enable all managed (ASP.NET) modules to run for all requests and therefore serve up the app_offline.htm for all requests.

In a lot of cases, you’ll likely be taking your site offline while retaining (or copying over instantly) your site’s web.config, and you probably already have runAllManagedModulesForAllRequests set to true or other modules present which dictate that ASP.NET should handle the request. You’ll be error free in this case, but if you ever remove the web.config during the outage you’re in trouble.

Conclusion

The app_offline.htm feature of ASP.NET is not the be all, end all, magical way to turn your entire application off in a friendly way for MVC applications. Because a lot of requests for an MVC application go to resources that first appear not to be managed by ASP.NET (friendly, extension-less urls), it’s vital that IIS be told to invoke ASP.NET for all possible requests, and this requires the presence of a web.config file stating as such.

If you are going to remove your application’s web.config file during site maintenance, you must also include a temporary web.config that specifies runAllManagedModulesForAllRequests=”true” along with the app_offline.htm file.

My bike ride around Manhattan

July 6, 2010

Before I left New York for good, I pulled out my bike and did something I’ve always wanted to do – rode it all the way around the perimeter of Manhattan.

I put together a little page with all the photos I took along with a map of the locations, so rather than repeat myself any further here, if you’re interested, head on over to Bike Around Manhattan.

Manhattan skyline in far distance

Tags: photos, nyc, biking
Categories: Miscellaneous

Getting started with SQLite and .NET

February 16, 2010

SQLite is a “self-contained, serverless, zero-configuration, transactional SQL database engine.” It is utilized in a few systems you may have heard of: Firefox, Skype, iPhone, and Andriod to name a few. The entire database is stored in a single file, which means your application or website can utilize a fully functional relational database without the constraints or costs of a traditional database server.

So when you don’t want to shell out the cash for SQL Server, your host doesn’t offer MySQL, and you’re tired of dancing around XML files as a database alternative, you can turn to SQLite!

System.Data.SQLite

You can install and use the core SQLite library on the official download page, but as a .NET developer your best bet is go with System.Data.SQLite – an ADO.NET provider for the SQLite engine. It also includes design-time support in Visual Studio 2005/2008!

I’m going to demonstrate the full process of setup using a simple C# .NET console application:

Install System.Data.SQLite from sqlite.phxsoftware.com

Include Visual Studio support for the version(s) desired.

sqlite ado.net provider installer sqlite designer installation

Create a new application, reference System.Data.SQLite

I’ve created a simple console application.

add reference to system.data.sqlite System.Data.SQLite referenced

Create a new database

Go to the Server Explorer and add a new Connection. Select SQLite as the data source, and on the following screen click “New…” to specify the name and location of the database you wish to create. Click OK and you’ve just established your connection!

Note: there is no specific naming convention for the file extension, and in this case I did not provide a file extension at all. Using something like .sqlite, .db, or .sdb all make sense to me. SQLite Administrator (a freeware GUI tool) seems to expect .sdb as the default file extension, whereas SQLite Manager (a Firefox addon) looks for .sqlite files by default.

SQLite change data source SQLite add connection

Right click on the new connection and view properties to examine the connection string. In my case it is: data source="C:\path\to\my\project\SQLiteFun\SQLiteDb"

Add a new table

Expand the database connection and right-click “Add New Table.” The table designer is still in development, so it’s important to note that you don’t have to use Visual Studio as the GUI tool for the database. There are a number of 3rd party tools you can use, and I’ll mention a couple below.

SQLite add new table SQLite add new table pt2

I’ve created a table named “Colors” and filled it with some data just for this demonstration.

SQLite table retrieve data

Write some traditional ADO.NET code

The System.Data.SQLite namespace contains all the classes used below (SQLiteConnection, SQLiteCommand, SQLiteDataReader). Here I’m using the typical ADO.NET way of creating a connection, a command, and executing a datareader. The name and hex database fields are outputted to the console one record at a time.

static void Main(string[] args)
{
    string connStr = @"data source=""C:\path-to-my-project\SQLiteFun\SQLiteDb""";
    string sql = "select * from Colors";

    using (SQLiteConnection conn = new SQLiteConnection(connStr))
    {
        SQLiteCommand cmd = new SQLiteCommand(sql, conn);
        SQLiteDataReader rdr = null;
        conn.Open();
        try
        {
            rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            while (rdr.Read())
            {
                Console.WriteLine(rdr["name"] + " " + rdr["hex"]);
            }
        }
        finally
        {
            rdr.Close();
        }
    }

    Console.Read();
}

And the output:

program output

That’s it!

That’s all there is to get started with SQLite in .NET using System.Data.SQLite!

GUI Tools

There are a number of third party GUI tools to interact with your SQLite database (thus, installing and using Visual Studio design-time support is purely optional). Below are examples of two of them in use.

SQlite Administrator

SQLite Administrator is a great little freeware tool supporting multiple languages and many features.

SQLite Administrator GUI

Firefox plugin

SQLite Manager is a Firefox addon (or see project hosted on google code: http://code.google.com/p/sqlite-manager/)

SQLite Manager GUI

Next up: SQLite with ASP.NET

In the beginning of this article I alluded to the fact that you may choose to use SQLite as a free database alternative to a paid SQL Server (or other) host, but I’ve completely ignored ASP.NET in this article.

I’m going to tinker with SQLite some more, using it with ASP.NET both locally and on a shared hosting provider. The results I will leave for a follow-up article.

About me

I'm Kurt, and I make web applications. Want to know more? Check out my about page.

WTF is all this code? I came here for food!

My wife made a new year's resolution to try out at least one new recipe each week. Want to know what she's been feeding me? resolutionfood.blogspot.com