Background Tasks in ASP.net (Web Services or API)

I just came across a System.Threading.Timer issue and thought I might share it with the community:

As part of a background task that pulls data out of Vision and sends it to a 3rd party I implemented a background task into a ASP.net Web Service using the System.Threading.Timer and TimerCallback.

private static System.Threading.Timer AppTimer

System.Threading.TimerCallback tab = SomeClass.SomeMethod;
AppTimer = new System.Threading.Timer(tcb, null, Properties.Settings.Default.Interval, Properties.Settings.Default.Interval);

What I found is that instead of the timer executing the method I specified every x seconds (as defined in the web.config) it continuously fired away ever second which put a lot of stress onto the server.

After digging around I came across this relatively simple method to run background tasks using the cache and reacting on the CacheItemRemoved event.

In a nutshell you basically add a cache item to your application with a specific expiration date/time, wait until that cache is removed by ASP.net and then do something at that point.

The nice thing about it is that you can give your cache item specific names and so implement multiple tasks like so

using System.Web.Caching;

public class Global : System.Web.HttpApplication
{
    private static CacheItemRemovedCallback OnCacheRemove = null;
    private void AddTask(string name, int seconds)
    {
        OnCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
        HttpRuntime.Cache.Insert(name, seconds, null,
            DateTime.UtcNow(AddSeconds(seconds), Cache.NoSliding.Expiration,
            CacheItemPriority.NotRemovable, OnCacheRemove));
    }
    public void CacheItemRemoved(string key, object value, CacheItemRemovedReason reason)
    {
        //do something based on the key value
        switch (key)
        {
            case "Task A":
                MyClass.DoSomethingForTaskA();
                break;
            case "Task B":
                MyClass.DoSomethingForTaskB();
                break;
            default:
                break;
        }
        //re-schedule the task cache item 
        AddTask(key, Convert.ToInt32(value));
    }
    protected void Application_Start(object sender, EventArgs e)
    {
        AddTask("Task A", 60);
        AddTask("Task B", 120);
    }
}

Important:
ASP.net checks the cache only every 20 seconds so always use a multiple of 20 for your intervals. Anything in-between will only trigger within the next 20 seconds. So this won’t work if you need intervals with high execution rates (5 or 10 seconds)