8

In the interest of always showing a "friendly" error page to users when they visit a site I have a catch-all at the in the Global.asax page, the majority of errors are handled by filters which seems to be the preferred method. For the most part, this works fine. However, during Application_Start, the Application_Error event (understandably) does not get triggered.

My Application_Start event contains some initialisation code which is dependent on a service call, so an easily defined point of failure is if the service is unavailable for whatever reason. The only way I've found to get around this is to do the following.

    private static Exception StartUpException;
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        Initialise();       
    }

    private void Initialise()
    {
        StartUpException = null;
        try
        {
            Bootstrapper.Initialise();
        }
        catch (Exception ex)
        {
            StartUpException = ex;
        }
    }

Then I have the following code in the Application_BeginRequest

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (StartUpException != null)
        {
            HandleErrorAndRedirect(StartUpException);
            HttpRuntime.UnloadAppDomain();
            Response.End();
        }
    }

This works, but seems like a bit of a hack. I'm also not sure about the consequences of calling UnloadAppDomain, or what would happen if multiple requests arrived. Is there a better way to manage this?

DJG
  • 205
  • 4
  • 8
  • Does `GlobalFilters.Filters` include `HandleError`? If so, that is catching all errors. – alexn Apr 29 '13 at 16:19
  • No I've removed that. – DJG Apr 29 '13 at 16:20
  • Excuse my saying, but surely having your application_start depend on a service is a bit of a [IMHO] bad-move? Is there no way this could be moved elsewhere? As the App start is a bit heavy! I would also expect if it does fail, and then unloads, that the next request to come in would then either be waiting for an app_start to complete and then pickup the thread, or call another App_Start which would then fail.. – Stuart.Sklinar Apr 29 '13 at 16:25
  • You may be right, but I'm not sure where else I could put this really. Within the Initialise code, I'm configuring the Unity container which will inject a wrapper class for the service to each controller. The wrapper class contains a couple of dependencies itself which load data from the service in their constructor. These dependencies are configured to be Singletons so this load should only occur once and not per request. – DJG Apr 29 '13 at 16:57

1 Answers1

4

We're having issues with bootstrapping in App_Start because HttpContext was not set and some of the bootstapped classes needed it; anyway this should work for your case as well:

public class MvcApplication : System.Web.HttpApplication {    
    protected void Application_BeginRequest() {
        var context = this.Context;
        FirstTimeInitializer.Init(context);
    }

    private static class FirstTimeInitializer {
        private static bool s_IsInitialized = false;
        private static Object s_SyncRoot = new Object();

        public static void Init(HttpContext context) {
            if (s_IsInitialized) {
                return;
            }

            lock (s_SyncRoot) {
                if (s_IsInitialized) {
                    return;
                }

                // bootstrap

                s_IsInitialized = true;
            }
        }
    }
}
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89