SharePoint: Successfully Debugging Custom Timer Jobs

Timer Job
You can even write a timer job to send you an email when your eggs are done.

I’ve developed and debugged my share of custom SharePoint Timer Jobs in my day, yet there is still a rather tricky ‘gotcha’ that seems to trip me up every time, even though I am well aware of it. Perhaps writing this article about it will help me remember next time?

My debugging style tends to be something like this: Change a line of code, run the change in debug mode. Change a line of code, run it in debug mode. You get the picture. While not always the most efficient way, it’s a fairly reasonable way to get the job done. Once my change allows the debugger to get past the error that was being thrown, I know I can move on to the next part of the logic.

However, when you’re dealing with SharePoint, no process is this simple. SharePoint likes to cache lots of stuff, sometimes causing it to behave in a somewhat unexpected manner. The same goes for DLLs. In order to increase system performance, SharePoint’s timer service caches all of the assemblies it needs to run all defined timer jobs, including any custom-developed jobs.

The Services window on Windows Server 2008 R2 Standard

So, what does this mean?

Even if you change your code and redeploy the solution to SharePoint, the Timer Job will execute using the old, cached DLL, rather than the new DLL from the GAC. The Visual Studio debugger will be unaware that it is not using the new DLL, and can lead to some interesting results. If the debugger seems to be acting like a drunken mental patient, this is huge clue that SharePoint is running the old DLL.

Remember this:

EVERY time you make a single change to your timer job and wish to debug, you must restart the Windows SharePoint Services Timer service in SharePoint 2007, and the SharePoint 2010 Timer service in SharePoint 2010. This can be done by navigating to Start > Administrative Tools > Services, right-clicking on the service, and selecting Restart. The next time the job runs, it will use the new version of the DLL that you deployed.

To avoid this problem, only one additional step is necessary in my debugging process. It’s simple and easy, but it manages to get me every time.