Summary
I am using Cache to serve advertisments, and to accumulate display and click counts. This all works very efficiently, but the usage data is accummulated in memory. I want this in-memory data to be written to the database at least once a day, plus if the application terminates. What is the best way of doing this? I have thought of using a timer, or perhaps there areCache events I can use. Or something else.
Detail
By cacheing the Advertisements datatable and the count array in which statistics are accumulated, the time to serve an ad was reduced from 16milliseconds to 0 milliseconds. I am using an ImageButton rather than an Adrotator as I found it easier to duplicate the Adrotator function explicitly than to figure out how to get information on which ad was being displayed.
A group of related Cache objects are created in the Pre-Render event of my master page, like this: -
If IsNothing(Cache("tbadvert")) Then
Dim taAdvert As New AdvertiserTableAdapters.AdvertismentsTableAdapter
Dim tbAdvert As Advertiser.AdvertismentsDataTable
tbAdvert = taAdvert.GetData
Cache("tbadvert") = tbAdvert
Dim Upbound As Integer = tbAdvert.Count - 1
Dim AdvertCountTable(Upbound, 2) As Integer
Cache("AdvertCountTable") = AdvertCountTable
Dim trAdvert As Advertiser.AdvertismentsRow
Dim AdvertIDTable(Upbound) As Guid
For Subscr As Integer = 0 To Upbound
trAdvert = tbAdvert(Subscr)
AdvertIDTable(Subscr) = trAdvert.AVTid
Next
Cache("AdvertIDTable") = AdvertIDTable
End If
Immediately following (still in pre-render) the page chooses (randomly) an ad to display, and adds 1 to the relevant impression count: -
If Cache("tbadvert").count = 0 Then
ImbHeaderAd1.Visible = False
Else
Dim R As New Random
Dim Subscr As Integer = R.Next Mod Cache("tbadvert").Count
Dim trAdvert As Advertiser.AdvertismentsRow = Cache("tbadvert")(Subscr)
ImbHeaderAd1.ImageUrl = "~/HttpHandlers/avtimage.ashx?id=" & Subscr
ImbHeaderAd1.PostBackUrl = "~/Admin_Pages/adredirect.aspx?ID=" & Subscr
Cache("AdvertCountTable")(Subscr, 0) += 1
End If
The redirect page Admin_Pages/adredirect.aspx executes this code in its Page_Load, adding one to the click count and then redirecting to the appropriate page: -
Dim Subscr As Integer = Request("ID")
Dim trAdvert As Advertiser.AdvertismentsRow = Cache("tbadvert")(Subscr)
Cache("AdvertCountTable")(Subscr, 1) += 1
Response.Redirect("http://" & trAdvert.AVTNavigateURL)
So far so good, although I'm concerned about an issue: -
Question 1.
I have used "IsNothing(Cache("tbadvert"))" as a single test for all of the related cache objects. Is this safe code? Or would it be better practice to put all of these objects into a single structure, creating a type like this and cacheing it as a single unit?
Structure AdData
Dim tbAdvert As Advertiser.AdvertismentsDataTable
Dim Ubound as Integer
Dim AdCounts(Ubound, 1) as Integer
End Structure
I read that there were some overheads with structures and so I used
independent variables, but I'm concerned that I may have introduced
some subtle error possibilities through possiblities of the cache
entries being independently created and/or released.
Continuing...
Anyway, so far so good, this all works perfectly, and is very fast, but of course the statistics are accumulated in memory. For testing I wrote a subroutine that writes the data out when I click a button: -
Sub WriteAdCounts()
' Write out accumulated Ad statistics, then clear table for next time
If IsNothing(Context.Cache("AdvertCountTable")) Then ' Defensive
Exit Sub
End If
Dim Ubound As Integer = Context.Cache("tbadvert").Count - 1
Dim taAdCount As New AdvertiserTableAdapters.AdCountsTableAdapter
Dim RecordTime As DateTime = Now() ' All records of batch have the same timestamp, rather than using Now() directly
For Subscr As Integer = 0 To Ubound
taAdCount.Insert(Subscr, RecordTime, Context.Cache("AdvertIDTable")(Subscr), Context.Cache("AdvertCountTable")(Subscr, 0), _
Context.Cache("AdvertCountTable")(Subscr, 1))
Context.Cache("AdvertCountTable")(Subscr, 0) = 0
Context.Cache("AdvertCountTable")(Subscr, 1) = 0
Next
End Sub
Question 2
How do I get this to execute automatically, at least once a day, and if the cache is destroyed. I wondered about using a timer in Global.asax, but I couldn't seem to hook up any event code to this, and also it would have left unhandled the issue of "what if the cache is cleared?". Perhaps there are cache events that I can hook up to.
Thank you, Robert Barnes