Custom error page in ASP.NET when database connectivity is lost.
Friday, March 21, 2008 at 5:08PM 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
- It generates internal server errors.
- It's not the type of error that can be fixed by be the developer.
- The problem tends to get solved by itself (think: reboot of the database server)
- Errors don't get logged (well, assuming that you are logging errors in the database).
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...).
