Scheduled Execution in ASP.NET

On a .NET-based project, I had the need to run scheduled maintenance tasks on the web server. My first preference was building a Windows Service or a Console Application (and scheduling it using the Windows Scheduler to run at regular intervals). However, this option was not feasible considering that the client for whom I am developing the application plans to host it in a shared hosting environment where they don’t have the privilege to deploy & run a Windows Service or Console Applications. So I had to come-up with an alternate approach, something that’s robust, efficient and flexible – if not as suitable for the concerned task as a Windows Service or a Console Application.

I read many similar concerns about scheduled execution using ASP.NET by fellow programmers on the community discussion forums. I finally came across an article on how to Force ASP.NET Apps to Keep-Alive by Paul Wilson. At first sight, it had the precise solution to what I was looking for – a simple Timer and Thread based workaround to pre-compilation plus background event invocation. Paul’s approach basically involves making the Global.asax file to inherit from his custom GlobalBase class (instead of System.Web.HttpApplication). It also exhibits an Application_Elapsed event which is pretty much what I needed.

Paul’s solution worked just fine in terms of its primary objective – force ASP.NET apps to keep-alive. However, I encountered a strange problem with the Application_Elapsed event. For some reason, the event was being triggered twice on each timer invocation. I spent sometime trying to figure out the cause of this behavior and even talked to Paul on what could be the problem. Paul was pretty busy with some other stuff so I decided to take another walkthrough of the GlobalBase class. While everything seemed fine in Paul’s code, an unexpected name change did the trick. First a quick glance at the snippet (modified to show only relevant code) from the class:

Namespace Wilson.WebCompile< ?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

????? Public Class GlobalBase

??????????? Inherits System.Web.HttpApplication

?

??????????? Private Shared _timer As System.Timers.Timer = Nothing

?

??????????? Public Event Elapsed As EventHandler

????? :

????? :

??????????? Public Overrides Sub Init()

??????????? :

??????????? :

??????????????????? _timer = New System.Timers.Timer(60000 * Me.KeepAliveMinutes)

??????????????????? AddHandler _timer.Elapsed, AddressOf KeepAlive

??????????????????? _timer.Start()

??????????? :

??????????? :

??????????? End Sub

?

??????????? Private Sub KeepAlive(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)

??????????? :

??????????? :

??????????? End Sub

????? :

????? :

????? End Class

End Namespace

I simply changed the name of the Event/EventHandler from Elapsed (to myElapsed) and it worked. The Application_Elapsed event (in the Global.asax file) was now being triggered only once per timer call as intended. However, I still haven’t been able to understand what’s the reason behind this behavior. My guess is that the Elapsed EventHandler of the class was somehow colliding with the Timer’s Elapsed event. Maybe someone has an explanation to it.

As Paul has also mentioned in his article that this approach of forcing apps to keep-alive is just a “hack”. It doesn’t guarantee timed execution on the server. But I’m pretty sure its robust & time-tested as Paul has been using it on his site for quite a long time now.