Simple Answer
There are times you need to take an ASP.NET web application offline. In general, the way to do so is place an App_Offline.htm file into the root of the web application. The ASP.NET application looks for that with every request, if it see it then it will display that page vice the requested page.
My Problem
The one problem I have with this is that due to security at work, I need a system administrator to touch the web servers outside of the development network (even as the project lead, I’m not allowed to touch the production server). Last week we had issues with the system due to some maintenance done on the database. I wasn’t able to get a hold of the DBA to fix that problem and the on-call web administrator was not acting promptly enough to upload an App_Offline page I provided them.
So, for about five hours people were getting errors as soon as they logged into the system. And wouldn’t you know this was a weekend that a lot of people decided to try to get things done. Normally, almost nobody goes into the system during the weekend.
My Solution
With the events of last weekend, I decided that I needed to find a way to take the application offline for such problems without having to get the system administrator involved. I did a lot of searching around the web and almost everything simply talked about the App_Offline solution. The idea I came up with was to use a flag in the HTTP Application State to indicate whether the application was offline or not. Then I would have the Application_BeginRequest event look at that, if the application was offline then direct to a page that told the user that the application was offline. I describe this solution in detail below.
I would assume that you would add this solution to an existing web application, but for the purpose of this blog entry, I have created a new ASP.NET Web Application that I have called “ApplicationOfflineExample.”
ApplicationStateHelper Class
The first thing you will want to do with your application is add the ApplicationStateHelper class described below. The purpose of this class is to provide helper methods for accessing the variables stored in the HTTP Application State. The code for this class is as such:
Public NotInheritable Class ApplicationStateHelper ''' <summary> ''' Gets or sets a value indicating whether the application is offline. ''' </summary> ''' <value><c>True</c> if the application is offline; otherwise, <c>False</c>.</value> ''' <revisions> ''' <revision date="4/4/2009" author="CEG" version="1.00.00.000">Initial Development</revision> ''' </revisions> Public Shared Property ApplicationOffline() As Boolean Get If IsNothing(HttpContext.Current.Application.Item("ApplicationOffline")) = True _OrElse TypeOf HttpContext.Current.Application.Item("ApplicationOffline") Is Boolean = False Then HttpContext.Current.Application.Add("ApplicationOffline", False) End If Return DirectCast(HttpContext.Current.Application.Item("ApplicationOffline"), Boolean) End Get Set(ByVal value As Boolean) If IsNothing(HttpContext.Current.Application.Item("ApplicationOffline")) Then HttpContext.Current.Application.Add("ApplicationOffline", value) Else HttpContext.Current.Application.Item("ApplicationOffline") = value End If End Set End Property ''' <summary> ''' Gets or sets the application offline message. ''' </summary> ''' <value>The application offline message.</value> ''' <revisions> ''' <revision date="4/4/2009" author="Chad Green" version="1.00.00.000">Initial Development</revision> ''' </revisions> Public Shared Property ApplicationOfflineMessage() As String Get If IsNothing(HttpContext.Current.Application.Item("ApplicationOfflineMessage")) = True _OrElse TypeOf HttpContext.Current.Application.Item("ApplicationOfflineMessage") Is String = False Then HttpContext.Current.Application.Add("ApplicationOfflineMessage", _"Application offline. Try again later.") End If Return DirectCast(HttpContext.Current.Application.Item("ApplicationOfflineMessage"), String) End Get Set(ByVal value As String) If IsNothing(HttpContext.Current.Application.Item("ApplicationOfflineMessage")) Then HttpContext.Current.Application.Add("ApplicationOfflineMessage", value) Else HttpContext.Current.Application.Item("ApplicationOfflineMessage") = value End If End Set End PropertyEnd Class
As you can see, we have two shared (static) property values. The first one, ApplicationOffline, is a flag that indicates whether the application is offline or not. The second, ApplicationOfflineMessage, stores the message that will be displayed to users when the application is offline. The properties values are shared in order to provide quicker and easier access to the values throughout the web application.
Site Administration Web Page
In order to be able to set the offline status of the web application, I have added a web page, SiteAdministration.aspx, that provides the necessary capability. The page contains several elements, including an indication as to the application’s offline status, a text box to specify the message displayed when the application is offline, and a button to switch the application offline status. I have also added a Return Home link to make using this demo easier.
<html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Site Administration</title> </head> <body> <form id="frmSiteAdministration" runat="server"> <p>The purpose of this page is to provide administration of the site.</p> <hr /> <h1>Site Status</h1> <p>The site is currently <asp:Label ID="lblSiteStatus"runat="server"Text="Online"Font-Bold="true"ForeColor="Black" />.</p> <p>Offline Message: <asp:TextBox ID="txtOfflineMessage"runat="server"TextMode="MultiLine"Rows="5"Width="300" /></p> <p><asp:Button ID="btnChangeSiteStatus" runat="server" Text="Take Site Offline" /></p> <hr /> <p><a href="Default.aspx">Return Home</a></p> </form> </body></html>
In the code behind we have the following procedures.
Private Sub PrepareSiteStatusSection() If ApplicationStateHelper.ApplicationOffline Then lblSiteStatus.Text = "Offline" lblSiteStatus.ForeColor = Drawing.Color.Red btnChangeSiteStatus.Text = "Bring Site Back Online" Else lblSiteStatus.Text = "Online" lblSiteStatus.ForeColor = Drawing.Color.Black btnChangeSiteStatus.Text = "Take Site Offline" End If txtOfflineMessage.Text = ApplicationStateHelper.ApplicationOfflineMessageEnd Sub
The PrepareSiteStatusSection takes the application offline status information and populates the appropriate details on the page. This method is used later when updating the page.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then PrepareSiteStatusSection() End IfEnd Sub
Then we have the Page_Load method. The only thing we are doing here is calling the PrepareSiteStatusSection method to populate Site Status section of the page.
Private Sub btnChangeSiteStatus_Click(ByVal sender As Object, _ByVal e As System.EventArgs) Handles btnChangeSiteStatus.Click ApplicationStateHelper.ApplicationOffline = Not ApplicationStateHelper.ApplicationOffline ApplicationStateHelper.ApplicationOfflineMessage = txtOfflineMessage.Text PrepareSiteStatusSection()End Sub
Finally we have the button click event handler code that will either take the application offline or back online.
Application Offline Web Page
Next, we add a web page that will be used to inform users that the application is offline.
<html xmlns="http://www.w3.org/1999/xhtml" > <head id="Head1" runat="server"> <title>Application Offline</title> </head> <body> <form id="frmApplicationOffline" runat="server"> <asp:Label ID="lblOfflineMessage" runat="server" /> </form> </body></html>
As you can see, this page is very simple and just includes a label that we’ll populate in the page’s load event seen below.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then lblOfflineMessage.Text = ApplicationStateHelper.ApplicationOfflineMessage End IfEnd Sub
Global Application Class
Finally, we need to modify the Application_BeginRequest method in the Global Application Class (Global.asax). If your application does not have such, make sure to add it now. Then you want to add the If clause shown below to the Application_BeginRequest method.
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) If Request.Path <> "/SiteAdministration.aspx" AndAlso _Request.Path <> "/ApplicationOffline.aspx" Then If ApplicationStateHelper.ApplicationOffline Then Response.Redirect("ApplicationOffline.aspx") End If End IfEnd Sub
First thing we do is ensure that the application is not serving up the SiteAdminsitration or ApplicationOffline pages. Obviously we want those to continue to work. Next we are looking at the ApplicationOffline variable from the ApplicationStateHelper. If it is set to the True, then we redirect to the ApplicationOffline page.
Results
Now, if you run the application everything will work. Once you go to the Site Administration page and click the Take Site Offline button, users will no longer be able to access the application web pages other than the Site Administration page (which you would use some type of authorization method to only allow authorized users to the page).
The only caveat I have found so far is that if your application gets restarted for any reason, the offline flag will return to false allowing users to access the whole application.
Download Example Solution Here