Custom error page in ASP.NET when database connectivity is lost.

A particularly annoying, yet frequent, issue for your ASP.NET is the loss of database connectivity. Indeed, if your database is hosted on a separate machine (as it is generally advised for performance), then your web application is subject to database downtime.

Database downtimes have several particularities

Thus, for my own ASP.NET application, I want to display an error page that invites people to try again at a later time whenever a database downtime occurs. In comparison, if a “real” error is encountered, the error gets logged and the customer is invited to contact the support (although, support is also monitoring server side error logs on its own).

Although, ASP.NET makes it very easy to add a generic error page for all internal errors through the <customErrors/> section in the web.config, it’s not that simple to have a dedicated page that is selectively displayed for database connectivity issue. Thus, I have decided to come up with my own HttpModule that catches database connectivity error and performs a custom redirect.

using System;  
using System.Collections.Generic;  
using System.Data.SqlClient;  
using System.Text;  
using System.Web;  
  
namespace Lokad.Web.Modules  
{  
    public class DatabaseConnectionErrorModule : IHttpModule  
    {  
        public void Init(HttpApplication context)  
        {  
            context.Error += new EventHandler(OnError);  
        }  
  
        public void Dispose() { }  
  
        protected virtual void OnError(object sender, EventArgs args)  
        {  
            HttpApplication application = (HttpApplication) sender;  
              
            // The SQL exception might have been wrapped into other exceptions.  
            Exception exception = application.Server.GetLastError();  
            while (exception != null && exception as SqlException == null)  
            {  
                exception = exception.InnerException;  
            }  
  
            if (exception as SqlException != null)  
            {  
                try  
                {  
                    // HACK: no SqlConnection.TryOpen() method.  
                    // Relying on error numbers seems risky because there are  
                    // different numbers that can reflect a connectivity problem.  
                    using (SqlConnection connection = new SqlConnection("foobar"))  
                    {  
                        connection.Open();  
                    }  
                }  
                catch (SqlException)  
                {  
                    application.Response.Redirect("~/MyError.aspx", true);  
                }  
            }  
        }  
    }
}

Finally, add a <httpModules/> section to your web.config, and you’re done.

Ps: I have been suggested to use the Global.asax hook. I have discarded this approach, because no matter how I was looking at the problem, Global.asax just looks legacy to me (zero modularity, zero testability, etc…).


Reader Comments (1)

Normally the Global.asax is better for the same modularity/simplicity reasons. You just pass any unhandled exception from there to your ExceptionPolicy instance in the application-scoped IoC container (a couple of LOCs that do not need testing). And ExceptionPolicy could do the rest in exception-specific and configurable manner (i.e. simply log DB connectivity downtimes, notify devs about some config problems etc) March 22, 2008 | Rinat Abdullin