Probably most of You are aware of the app_offline.htm functionality. Basically if you put a html file named app_offline.htm in the root of a web application, the application goes to "offline" mode where all incoming requests are redirected to this file.
This seems great at first sight. You can temporarily disable the application while performing some maintenance. Specifically, you can delete all application files except the app_offline.htm and the application still works (even though the web.config is gone!) As long as the maintenance is completed you just remove or rename the app_offline.htm and the application is back from the void.
There is, however, one caveat and one drawback of this feature.
The caveat is that the app_offline.htm file must be longer that 512 bytes otherwise instead of its content you get ... 404 (can someone explain it?).
The drawback is that the offline mode affects everyone including you! Either anyone or noone can access the application. What would be nice, however, is to have the ability to temporarily redirect requests coming from outside but still be able to use the application locally.
The code below shows how to accomplish that requirement with really simple HTTP handler. To use it you have to:
- compile the source class
- add the handler section to the web.config file and put appoffline.htm (without the _ !) in the root of the application
1: <httpHandlers>
2: <add verb="*" path="*.aspx" type="AppOffline.AppOfflineHandler, AppOffline" />
3: </httpHandlers>
Handler code:
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4: using System.Web;
5: using System.IO;
6: using System.Web.UI;
7:
8: /* Wiktor Zychla, 2007 */
9: namespace AppOffline
10: {
11: public class AppOfflineHandler : IHttpHandler
12: {
13: string appOffline;
14: /// <summary>
15: /// appoffline.htm file content as singleton
16: /// </summary>
17: public string AppOffline
18: {
19: get
20: {
21: if ( appOffline == null )
22: appOffline = OfflineFileContent;
23:
24: return appOffline;
25: }
26: }
27:
28: /// <summary>
29: /// Path to the appoffline.htm file
30: /// </summary>
31: public string OfflineFilePath
32: {
33: get
34: {
35: return context.Server.MapPath( "~/appoffline.htm" );
36: }
37: }
38:
39: /// <summary>
40: /// appoffline.htm file content
41: /// </summary>
42: public string OfflineFileContent
43: {
44: get
45: {
46: return File.ReadAllText( OfflineFilePath );
47: }
48: }
49:
50: /// <summary>
51: /// Is the application in the offline mode?
52: ///
53: /// Yes - if the appoffline.htm exists
54: /// </summary>
55: public bool IsOffline
56: {
57: get
58: {
59: return File.Exists( OfflineFilePath );
60: }
61: }
62:
63: HttpContext context;
64:
65: #region IHttpHandler Members
66: public bool IsReusable
67: {
68: get
69: {
70: return true;
71: }
72: }
73:
74: public void ProcessRequest( HttpContext context )
75: {
76: this.context = context;
77:
78: // offline mode and remote request?
79: if ( !context.Request.IsLocal &&
80: IsOffline
81: )
82: {
83: context.Response.Clear();
84: context.Response.Write( AppOffline );
85:
86: context.Response.End();
87: }
88: else
89: // redirect to the default processing pipe
90: PageParser.GetCompiledPageInstance(
91: context.Request.Path,
92: context.Request.PhysicalPath,
93: context ).ProcessRequest( context );
94: }
95: #endregion
96: }
97: }
This approach has its own drawback - it is not "maintenance" aware in a sense that when for example some crucial modules are gone from the /bin subfolder, the application will not load at all because of non-existent modules beeing referenced from within the web.config file.
The nice thing is that you can test the application locally but all remote requests are gracefully redirected to the appoffline.htm. I suggest then to use my feature side by side with the ASP.NET app_offline.htm.
1 comment:
Although a nice alternative, there might be a performance hit in checking a file for existence with every request. I suggest you to use a directory listener instead. You can make a static class that implements this listener and keep it alive in the app domain. You can add a property to the class that checks the state and automatically registers the listener if it doesn't exist yet (to cope with app domain flushes).
However, as you said, your alternative is not really in maintenance state. Remind that using app_ofline.htm also frees all the resources like database and file links. You probably want to have this when you upgrade important libraries...
Post a Comment