Whenever you do maintenance work on a website it is advisable to show the visitors a nice message telling them politely to come back later, rather than a nasty error, or even worse: a big Yellow Screen of Death.
Since ASP.NET 2.0 came out of the labs of Microsoft, there is a way to take a web application down using the “app_offline.htm” approach. You simply create a HTM file, which you then upload to the server, and if there is any request to this web application, IIS will automatically show the contents of the app_offline.htm file. Once uploaded, most people only rename the file so that it doesn't catch up with IIS anymore, and the site is already back online.
This approach comes in really handy when you upload new files to the server, and while the upload did not finish, there are already requests coming in. (Ex: somebody accesses your website - ~/default.aspx, and you have some logic in this page that references a class that has not been uploaded yet)
Where this approach simply doesn’t cut the mustard is when you want to restrict the access for visitors, but you still want to be able to access the site as an administrator (testing, problem investigation, general maintenance). The app_offline.htm approach is not good for this because simply everybody will get the content of the app_offline.htm file no matter what the requested page is.
In the quest for a good solution to this problem I had the following facts in mind:
- same sort of easy use like uploading the app_offline.htm (maybe a similar file to trigger the action)
- access granted based on the ip of the visitor (if AdminIP == RequestIP –> unrestricted surfing)
My current solution looks like this:
- The filter is triggered when a file named “offline.html” exists on the server. (This is practically the same idea as the app_offline.htm one)
- The web.config file contains an application settings key defining the Administrator IP
<add key="AdminIP" value="123.124.125.126" />
- To filter the unwanted IP addresses out, I’m using a HttpModule:
/// <summary>
/// This is how you take an ASP.NET application offline the
/// Arnold Matusz way with AppOfflineModule
/// </summary>
public class AppOfflineModule : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
if (File.Exists(Path.Combine(context.Server.MapPath("~"), "offline.html")))
{
string ip = context.Request.UserHostAddress;
string adminIP = ConfigurationManager.AppSettings["AdminIP"];
if (ip != adminIP)
{
context.RewritePath("~/offline.html");
}
}
}
}
As you can immediately see, on each Request, I’m performing a check for a file named offline.html with File.Exists(). If it exists I’m checking for the administrator IP in the web.config file to see if the request is coming for somebody that should not be restricted.
Adding your HttpModule is easy:
<httpModules>
...
<add name="AppOfflineModule" type="AppOfflineModule" />
...
</httpModules>
Once offline.html uploaded, each “restricted” visitor will only see the content of offline.html.
To disable the whole functionality you only need to rename the offline.html file to anything else (I suggest a difference of a character so that it can be easily renamed back: offlin.html).
In a very small maintenance group this solution works just fine, but for future work I’d definitely create some functionality to define more IP addresses which can access the website while it’s taken “offline”. Defining an IP class would also be another good idea, particularly when the number of “administrators” is very big.
There is little limit in the possibilities to identify who can and cannot access your website if you use this approach, you only need to program your logic into a BeginRequest event, and you are ready to go.