Preface
We have a very complex website, it involves recording everything that is ever rendered and some complex randomising of what we render. Our website is basically a pay per click revenue stream.
The Problem
Ok so the problem is, we rely on caching of a select number of data tables, this may sound silly to do but we are careful and we dont exceed the hardware capacity of the machine, and alas there is no other suitable method for us. The setup we have is IIS running in State Server mode using the ASP.NET state server Windows Service. Some of you will already know this is based on an XML filesystem structure to hold everything that gets placed into the cache.
Now for some reason state server started to break down and cause table and row corruption, we never managed to nail down why this was occuring since ASP.NET Datatables can be serialised and deserialised seemlessly from and to XML we concluded it was to do with asynchronous access to the objects in the cache breaking down. We needed to resolve the problem and we needed to do it now, I decided to write our own caching class that would sit in the Application Object.
The Solution
So a few basic rules here
1. The Class lives in the application object ergo when the website restarts the class disintigrates and re instantiates
2. The Class must be able to handle asynchronous access
3. The Class must offer similar features as ASP.NET cache, ie specifying lifetime of objects
4. The Class must also run maintenance on itself as a result of requirement 3
5. The Class must support Add, Get, Remove of datatables and objects
Ok so now we have some ground rules, it took me about a day to write, and the finished product should be attached to this post.
In your App_Code folder drop these three files (obviously rename them to .vb first).
ApplicationCache
itimer
SiteStart
Now heres how to use it.
1. Instantiate the class in the Global.asax file Application_Start routine (brings everything to life)
2. Attach a new timer to the maintenance event of the class _RunMaintenance (tells itself to cleanup)
3. Start the timer in a new thread .RunAsNewThread (opens the timer in a thread seperate from the application object, we like this seperation)
4. Add the class to the application object (so you can access it from anywhere in the app)
So starting in your global asax
|
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) 'Site global startup instantiation Dim SiteStart As New SiteStart SiteStart.TestSystemFlag = True SiteStart.StartUP() SiteStart.EventWrite("Site global.asax Application_Start()" & vbCrLf & vbCrLf & "Web Site Application is starting up", "StartUp", Diagnostics.EventLogEntryType.Information, False) End Sub |
Heres the code snippet you can use as an example of starting the class up, this can been seen inside SiteStart
|
'#### TABLE CACHING ############# 'create a new timer to run no a seperate thread once every 180 seconds (3 minutes) Dim Tm As iTimer = New Timer(180) 'create a new table caching mechanism and attach the event for the timer to its maintenance routine Dim TC As New AppTableCache(30, True, IIf(SiteStart.TestSystemFlag, 150, 500)) AddHandler Tm.TimerTick, AddressOf TC._RunMaintenance 'attach a routine from this class to log when the maintenance is running AddHandler TC.MaintenanceRunning, AddressOf Me.TCMaintenance 'tell the timer to start itself in a seperate thread Tm.StartAsNewThread() 'add the instance of the table caching class to the application object HttpContext.Current.Application.Add("TC", TC) '#### END TABLE CACHING ########## |
OK so now the class is active how do i call it i hear you ask, well you have a choice.
If you have a base page then add this to it
|
'Application table cache, used to store tables in teh application wide object Dim oTC As AppTableCache = HttpContext.Current.Application("TC") ''' <summary> ''' Returns the instance of the AppTableCache class within the application object ''' </summary> Public ReadOnly Property TC() As AppTableCache Get Return oTC End Get End Property |
If you dont then in your code behind file do this
|
Dim oTC As AppTableCache = HttpContext.Current.Application("TC") |
Once you have done one of the above you can make the calls like so
|
TC._AddTable("MyTable", 20I, False) TC._TableExists("MyTable")) Dim Tbl as DataTable = TC._GetTable("MyTable") |
Or
|
oTC._AddTable("MyTable", 20I, False) oTC._TableExists("MyTable")) Dim Tbl as DataTable = oTC._GetTable("MyTable") |
The reason we start a timer in a seperate thread is because we want to call the maintenance routine periodically and the only way to keep a timer allive from the application_start is to create a seperate thread, forget trying to place it in the application object or cache because it wont stay runtime, it will be deserialised into a static xml structure describing how to rebuild it.
Thats about it. You could attached a sub rountine that writes an information event to the windows event log when it runs, so you can make sure it works. You could also create a page that pulls out the current state of the class, ie how many tables its holding, what the names are etc etc.