19 September, 2008

Creating an ASP.NET simulated Windows Service

I've recently had the need of creating a "Windows Service like" behavior on my hosted website that allowed for a scheduled execution kind of operation. As I'm not able to install Windows Services on my website hosting company's servers, I need to resolve to another solution. With the great help of a college, we came up with this simple yet beautiful solution: Use the ASP.NET Cache for invoking a worker method on intervals.

To make this work - you need to register the cache object on the "page_load" event on a page in your application. This loading will insert an object in the cache. The trick here is to make this cache expire and to use the callback delegate on this expiration.

First of all - you need to make a dummy page (aspx) what is responsible for registering the cacheobject in the first place.

/// <summary>
///
Dummy page for registering a cache-entry.
/// </summary>
public partial class Retriever : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CacheRegistration.RegisterCacheEntry();
}
}



Next - the below shows the registration of the cache item. As evident from the cacheregistration - a delegate pointing to WorkerMethod is added in the cache registration.



/// <summary>
///
Registers the cache entry.
/// </summary>
public static void RegisterCacheEntry()
{
Logger.DebugWriteEnter("CacheRegistration.RegisterCacheEntry");

if (HttpContext.Current.Cache["cache"] != null)
return;

int intervalSec = Convert.ToInt32(ConfigurationManager.AppSettings["retrivelIntervalSec"]);

//register cache entry
HttpContext.Current.Cache.Add("cache", string.Empty, null, DateTime.MaxValue, TimeSpan.FromSeconds(intervalSec),
CacheItemPriority.High, new CacheItemRemovedCallback(WorkerMethod));

Logger.DebugWriteLeave("CacheRegistration.RegisterCacheEntry");
}


This will call the method below on cacheexpiration.



/// <summary>
///
This method is called on CacheExpiration (and will perform the work to do).
/// </summary>
/// <param name="key">
The key.</param>
/// <param name="value">
The value.</param>
/// <param name="reason">
The reason.</param>
static void WorkerMethod(string key, object value, CacheItemRemovedReason reason)
{
Logger.DebugWriteEnter("CacheRegistration.CallBackMethod");

//Do work here!

//make a call to retriver page to re-set the cache.
WebClient client = new WebClient();
client.DownloadData("http://<somesite>/retriever.aspx");

Logger.DebugWriteLeave("CacheRegistration.CallBackMethod");
}



To make sure the cache is registered again (to let it expire next time); you need to make a programmatic call to the page of interest using in this case a WebClient instance.


Now - you have a fully functional ecosystem working in the same manner as a windows service that allows you to execute repeated tasks in a scheduler like behavior. And in addition hosted at a remote provider. Simple and easy!

No comments:

InRiver: Not loading your extensions?

(You really need to in the loop to appreciate the issue this post addresses). Man, I've been fighting this problem for hours before I ...