tags:

views:

74

answers:

3

I'm writing an ASP.NET application. When a specific kind of request is being handled, I want to schedule a method to be called in a certain number of minutes after the request is handled. The postponed method does not need to communicate with the client that made the original request, it is just intended to do some "housekeeping" work. What is the best way to do this in an ASP.NET context? (It's ok to not fire the event if the application domain dies for some reason).

+1  A: 

You could start a timer (System.Timers.Timer) from one of the application event in global.asax.cs (e.g. in Application_BeginRequest) after checking that it is required for that request.

Then, in the handler of the timer's Elapsed event, make sure that you stop the timer.

E.g. put something like this into global.asax.cs:

System.Timers.Timer _timer = null;    
void Application_BeginRequest(object sender, EventArgs e)
{
  // check if cleanup must be initiated
  bool mustInitCleanup = RequestRequiresCleanup();
  if ((_timer == null) && mustInitCleanup)
  {
    _timer = new System.Timers.Timer(5000);
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);      
    _timer.Start();      
  }  
}

void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
  _timer.Stop();
  _timer = null;     
  // do cleanup task
}
M4N
+1  A: 

In Global.asax use this to check your incoming request:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        CheckRequest(HttpContext.Current.Request);
    }

if your request is valid, register a cache entry:

    private void CheckRequest(HttpRequest request)
    {
        if (request)
            RegisterCacheEntry();
    }

    private void RegisterCacheEntry()
    {
        if (HttpRuntime.Cache[CacheItemKey] == null)
        {
            HttpRuntime.Cache.Add(CacheItemKey, "your key", null, 
                DateTime.Now.AddSeconds(60), //change to fire in whatever time frame you require
                Cache.NoSlidingExpiration, 
                CacheItemPriority.NotRemovable,
                new CacheItemRemovedCallback(CacheItemRemovedCallback));
        }
    }

then process your function in the callback:

    private void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
    {
        // execute your function

    }
flesh
I like this solution the best; it's the one that gives me the strongest "duh, I should have thought of that myself." Thanks!
John Källén
A: 

Simply create a new thread to do the housekeeping work and at its beginning have it sleep for however long you want the server to wait before doing the action.

For example, somewhere in that specific request you want to call DoSomething:

        aNewThread = new Thread(Foo);
        aNewThread.Start();


    public void Foo()
    {
        Thread.Sleep(5000);
        DoSomething();
    }
JB King
The problem is that this solution ties up a thread with the sleep statement, probably not a good use of the megabyte of stack that thread consumes.
John Källén
While there may be a thread being tied up with a sleep statement, do you have a better action for a thread to do while waiting for x minutes to pass? There may be built in clean up jobs that an ASP.Net application pool has but I'm not sure how well I'd rely on that to work.
JB King