Recently I've seen quite a few questions pop up in regards to debugging ASP.NET application initialization. Most commonly I see something along these lines:

I'm trying to debug my ASP.NET application and am starting the Debugger, but it won't stop on code in my Application_Start event

Yup, been there done that.

What does Application_Start do?

Application_Start is pseudo handler that ASP.NET checks for during initialization of an ASP.NET application - if one exists it's fired during the application's initialization process which occurs specifically when the HttpRuntime instance is started. Effectively Application_Start is fired exactly once when the Web application's AppDomain starts. Application_Start is simply a short cut that makes it consistent with the other Application_ events that are available in global.asax.cs even though it is not actually an HttpApplication event like most other Application_ handlers. Remember that Global.asax is your application's subclass of the HttpApplication object:

public class Global : System.Web.HttpApplication

so Global.asax.cs inherits the HttpApplication and this instance is what ASP.NET uses to run your application. You can always access this instance with HttpContext.Current.HttpApplicationInstance. ASP.NET creates a pool of multiple HttpApplication instances that are assigned to each request being processed, but Application_Start fires only exactly once during the Web application's lifetime not for each instance of HttpApplication started.

Because Application_Start fires only when the HttpRuntime is initialized, it's a common hook point for application configuration tasks that need to happen only once during the lifetime of the application. It's perfect for setting static values that affect the entire running application or set up global configuration settings that get reused throughout the application. Application_Start can also be used to dynamically add new modules to the processing chain at runtime.

Application initialization extends beyond Application_Start. There's other code that fires during the one time initialization as well. HttpModules and their Init() handlers that fire to hook up the actual module events, also fire during this initialization stage. Likewise you can't debug these Init() handlers when debugging your code in the full version of IIS. I'm sure there's other code in ASP.NET that fires during application initialization but these two are the most common scenarios you might run into with user code.

IIS and Application_Start Debugging from Visual Studio

Problems with debugging Application_Start come up when you try to debug this initialization code when running the full version of IIS. It doesn't happen when you run the Visual Studio Web Server or IIS Express - it only occurs when you run the full version of IIS.

The problem is caused by the way that Visual Studio attaches the debugger to IIS when running ASP.NET applications, which occurs AFTER the application initialization phase and so is too late to actually stop on a breakpoint in Application_Start.

The code of course still executes, but the debugger doesn't trigger any breakpoints if you simply press F5 to debug in Visual Studio. If you set a break point like this (when running in full IIS):

the breakpoint won't trigger.

Likewise if you have code in an HttpModule's Init() handler which also fires as part of the runtime initialization code, the debugger won't trigger there either:

If you don't know what's happening it's easy to assume that this code is never firing, but that's not the case. The code fires, only the debugger is not triggered when the code is executed by IIS.

Easiest Solution: Use the Visual Studio Web Server or IIS Express

Debugging of Application_Start - and also HttpModule.Init() handlers - occurs only when running the full version of IIS. When running the Visual Studio built-in Web Server or IIS Express there's no problem debugging application initialization. So one easy solution to debugging Application_Init and Module Initialization code is to simply switch to using the built in Visual Studio Web Server (or IIS Express) as opposed to the full version of IIS:

Now if you press F5 to debug from within Visual Studio the debugger happily triggers on your breakpoint. This works because Visual Studio actually launches the local server EXE manually and so can easily attach the debugger on startup. Inside of IIS the application pool is actually loaded from the IIS Admin service and Visual Studio has to attach to the Application Pool Exe after it's been started.

If you're already running one of these local servers for all your debugging then you shouldn't really have run into this issue in the first place and this is certainly a good way to go. In many environments it makes perfect sense to run the local servers.

Even if you're like me and you prefer to run the full version of IIS, and you happen to need to debug your Application_Start or other initialization code it might be worthwhile to switch temporarily to one of the local servers to debug the issue. It's the easiest way to get past any issues you might have during application initialization.

Debugging IIS Initialization in Visual Studio

If you definitely need to debug your startup code in the full version of IIS there are other ways to get the debugger attached as well. It won't work with the F5 run menu and it requires a little more work.

You can use the System.Diagnostics.Debugger.Break() method to force the Web application to break into the debugger:

Add this code to your Application_Start or other initialization code like Module.Init() code where you want to break.

Before you do anything else do:

IISReset

from the Windows RUN box to ensure that IIS has been shut down and your Application Pool is in fact going to start up fresh.

Then open a page on your Web site.

When you hit this page, Visual Studio will pop up a debugger dialog like this:

Click yes, and Visual Studio will then start up a new instance and display your code. If your code is set for debugging (ie. the PDB file exists) you'll be able to step through your code and see watch and locals information.

Here's what the debugger session looks like:

You can see that now we're debugging the w3wp process directly. The debugger has attached using a different route bypassing the Visual Studio F5 startup and instead directly attaching the debugger to the process.

One downside of this setup is that you can't see your entire project while debugging this way, but you can step into any code that symbols (PDB files) are available for. So if you needed to step into a module that resides in a separate assembly for example you can do that as long as that assembly and the .pdb file is available.

Summary

Hopefully you don't have a lot of code in your Web application's initialization code and hopefully you never actually need to debug it :-) Even if you do have to debug your startup code it's not likely to be a frequent task.

But it does come in handy at times to be able to do so directly in IIS so you can see the entire IIS environment including parent hierarchy and modules that are loading up in your application. In the past I've had some nasty module configuration conflicts between my virtual and the parent directories and being able to step into the live environment directly in IIS was a lot easier than trying to write debug log information out to a log file.

It's one of those edge case issues that comes up very rarely, but when you need it, you'll be glad you know how to debug your code in the live environment…

The Voices of Reason

there ist actually another method you can use when you have multiple web applications running in the same application Pool:

You run your website in IIS and use the 'Attach to process' feature of the VS debugger to attach to the correct worker process (w3wp) for the application pool.

Then you go to the IIS manager and simply restart the application you want to debug (don't recycle the application pool though, because that would terminate the w3wp you're attached to).

Since the w3wp process still runs for the other application(s) in the same Application Pool, the application you just restarted will be initialized again on the next request and the debugger will hit, since you're still attached.

Great tips, Rick. I stumbled across a lazy man's way of accomplishing this using full IIS as well. You can set your breakpoint in Application_Start, begin debugging, then 'touch' a monitored file (e.g. delete and retype a character in web.config and then save), and then refresh your browser. IIS will reload the application (since a file was changed), but the debugger will catch the breakpoint in Application_Start when it starts up again.

It's certainly not a good method when doing serious debugging, but I've found it incredibly useful when I only needed to perform a quick step through to confirm something was still working as intended.

If the VS instance you use for the Debugger.Break() already has the correct project loaded, it will actually load the source file from the project (as long as the version being debugged is actually built from the same folder).

@Stefan - that's a great tip! Actually I have used that myself before now that you mention it, but I totally forgot about it.

@Knaģis - Hmmm... that's not happening for me. Even when starting with Debug or Run from within VS I get the debugger dialog first which asks to spin up a new instance of VS. Must be some sort of configuration issue.

Microsoft has fixed this in Visual Studio Ultimate 2015 Preview. Fixed it as in it's totally screwed up no matter what "server" you use. I'm running my Web site in IIS Express, and the Application_Start is never hit. Thanks, Microsoft. I'll go create a Connect issue so they can mark it "Closed. By design." To which, I'll once again reply, "Fire the designer."