Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Keeping Admins and clients happy with Cache usage

0.00/5 (No votes)
1 Oct 2004 1  
Optimization considerations for your code management
Download source code - 1.4 Kb

Intro

Being a server and database guy who got thrown into web programming, I still look to optimizing items with code when possible. Mainly that is because budgeting, staffing, and throughput concerns are always on the mind of Admins. After all, Admins love people who cause them to have to come in at pre-O'dark-thirty to reset something. Also from a business sense, if you adversely affect client business relationships with code you may be undermining your advancement abilities.

Resource used for this article

The 17th chapter of Steven Walther's ASP.NET Unleashed (Second Edition) struck a chord with me. It deals with cashing, and more specifically cashing that does not use cashing for the entire page.

Onwards

We all know that it is possible through includes to use .ascx pages to compartmentalize our repeatedly recycled sections of the page as a whole. After all it is tedious to have to perpetually cut and paste in header and footer code items. If you are not using .ascx pages for code reuse you must be working for a living or something. Myself, I have to bow to the phone and email so anything that gives me more time is a godsend.

Sure in my master .aspx page I could just have <%@ Outputcache Duration="300" % VaryByParam="None"> and save myself some typing. But as Steven points out, what happens if you rely upon banners ads for revenue generation? If you keep brining up the same banner, your other clients may begin to vacate due to a lack of hit-count. This is how your company might get paid after all in this model, or it may be a means to reducing workload for an Admin. Also what if one of your client's ad campaigns is only for a limited time? What if your layouts are time specific? Like for a sweepstakes, if it is dependant upon a holiday/event theme, or if the banner is a coupon to be printed out and sent in for some time specific offer. Clients don't want it running forever and you don't want to wait until midnight to manually remove the ad or the xml file.

How about cashing on a item by item basis:
cache.Insert( "myItem", "Run that new ad!", _
New cacheDependancy( MapPath( "myAdFile.xml" ) ) )
So if the "myAdFile.xml" item is modified the mytItem is auto dumped from cache.

These items are using the cacheDependancy class for file dependencies

How about cashing based on on
multiple items that may be updated:

Dim myFiles( ) As String = _
{ MapPath( "myAdFile.xml" ), _
{ MapPath( "myAdFile2.xml" ), _
{ MapPath( "myAdFile3.xml" ) }

cache.Insert( "myItem", "Run that new ad", _
New cacheDependancy( myFiles ) )

In this case if any of the three .xml pages in the string array are modified the myItem is dropped from cache.

So in effect you could use it to drop the use of an XML file over the use of another in reserve. Or you could have a special color schema in XML for holiday related times of the year where background colors or other page attributes would be festive. Of course then you have times where you are away from the desk and an event, like a holiday, may be around the corner. For me that is X-MAS and college football bowl games (I mean New Years). Time to switch from red/white/green for Santa into black/silver/gold for Baby New Years. Now I need a trigger.

Now for some work in SQL Server to set up some triggers as this will be the helping item to make this happen. A trigger is basically a stored procedure that fires whenever a delete, insert, or update is made against a table or a view.

[Personal choice: use the view extensively so the actual table is not touched and be sure to validate everything the user enters first.
See also: http://msdn.microsoft.com/events/devdays/sessions/default.aspx
AND
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/ThreatCounter.asp
for the creation of "hack-proof" ASP.NET for more security considerations]

If you want you can also check out xp_cmdshell that runs a string as an operating system command to write a file to a directory.

So the MakeChng.sql item looks like this:

CREATE TRIGGER UpdateCache
On Products
FOR UPDATE, DELETE, INSERT
AS
DECLARE @CMD Varchar( 200 )
SELECT @cmd = 'echo ' + Cast( getDate( ) As Varchar 50 ) ) +
' > c:\layoutChng.txt'
EXEC master..xp_cmdshell @cmd, no_output

The layoutDepndsOn.aspx page would be:

<% Import Namespace="System.Data" %>
<% Import NameSpace="System.Data.SqlClient" %>

<Script Runat="Server">

Sub Page_Load
Dim dstProducts As DataSet

dstProducts = cache( "ProductsDS" )
If dstProducts IS Nothing Then
dstProducts = GetProducts( )
cache.Insert( "Products", dstProducts, _
New cacheDependancy( "c:\layoutChng.txt" ) )
End If
dgrdProducts.DataSource = dstProducts
dgrdProducts.DataBind( )
End Sub

Function GetProducts( ) as DataSet
Dim conNorthwind As SqlConnection
Dim strSelect As String
Dim dadProducts As SqlDataAdapter
Dim dstProducts As DataSet

conNorthwind = New SqlConnection( "Server=LocalHost;UID=BigAdmin;PWD=YeaRight;Database=Northwind" )
strSelect = "Select Top 20 * From Products Order By ProductID"
dadProducts = New SqlDataAdapter( strSelect, ConNorthwind )
dstProducts = New DataSet( )
dadProducts.Fill( dstProducts, "ProductsDS" )
Return dstProducts
End Function

</Script>

<HTML>
<head><title>layoutDepndsOn.aspx</title>
</head>
<body>
<asp: DataGrid ID="dgrdProducts" Runat = "Server" />
</body>
</HTML>


Or in the event you want to manually control it with a button click (from home or with the aid of an over-night control person) use this:
[Based on: "ASP.NET Unleashed" (Second Edition) by Steven Walther , pg 796-7]

<%@ Page %>
<Script Runat="Server">

Sub UpdateItem1( s As Object, e As EventArgs )
Cache( "item1" ) = txtNewValue.Text
End Sub

Sub UpdateItem2( s As Object, e As EventArgs )
Dim arrKeyDepends() As String = { "item1" }

Cache.Insert( "item2", txtNewValue.Text, _
New CacheDependency( Nothing, arrKeyDepends ) )
End Sub

</Script>
<html>
<head>
<title>Button Based Dependency - BBDepend.aspx</title>
</head>
<body>
<form runat="Server">
<asp:TextBox id="txtNewValue" Runat="Server" />
<p>
<asp:Button Text="Update Item1" OnClick="UpdateItem1" Runat="Server" ></asp:Button>
<asp:Button Text="Update Item2" OnClick="UpdateItem2" Runat="Server" ></asp:Button>
<hr />
Item1 = <%=Cache( "item1" )%>
<br />
Item2 = <%=Cache( "item2" )%>
</p>
</form>
</body>
</html>


Also I hope these tables above help as a quick reference.


Varying by parameter values: AS IN
<%@ outputcache duration="300" VaryByParam="none" %>


*
indicating that different cached versions of a page should be created whenever the page is requested with different parameters

none
indicating that different cached versions of a page should not be created whenever the page is requested with different parameters

PID
or something based on a query string to have different cached versions of a page based on each request.

Varying by Header attribute: AS IN
<%@ outputcache duration="300" VaryByParam="*" VaryByHeader="User-Agent" %>


User-Agent
by which browser to alter by based upon which browser is making the request

Varying by Custom String: AS IN
<%@ outputcache duration="300" VaryByParam="*" VaryByCustom="VBScript" %>
- - A function in the Global.asax file must be created for a custom string - -


VBScript
Dependant upon if the browser supports VBScript -- Use HttpBrowserCapabilities class to find major version, if it supports JAVA applets, etc.

Browser
The major version of the page will be cached; so for IE 5.0 and IE 5.5 the same thing will be cached.

Host

Accept - Language

Varying by location: AS IN
<%@ outputcache duration="300" VaryByParam="*" Location="Client" %>
- - This is browser-dependant though - -


Any
The Default value. so could be on any location including server, downstream servers, and the browser.

Client
To be cached only on the browser.

Downstream
In a server farm arrangement, on any server down the stream.

None
No page cashing to be made.

Server
cache it only on the server.

HttpCachePolicy Class
for more control




SetExpires( )
Used to have cache expire on an absolute date and time

Setcacheability( )
Used with setting as to how the page should be cached.

Nocache
Prevents cashing with cache-Control:no-cache header.

Private
Default value. Cannot be cached on proxy servers, but can be cached on a browser.

Public
Page can be cached on proxy servers and browsers

Server
Only to cache on the server

Memory use preservation via sharing cashed pages: AS IN
<%@ outputcache duration="300" VaryByParam="*" Shared="true" %>


Shared="true"
Used to share the cached item across multiple user controls.

Why an item was removed from Cache Log: Reasoning



DependencyChanged
Removed because of key or file dependency.

Expired
Expiration policy criteria was met causing it to be removed.

Removed
Removed by an explicit call to either Remove or Insert method

Underused
Removed do to lack of resources on the server.

I hope this helps with your working relationships with your various Admins, clients, or helps reduce your after hours visits.

Please do check out this very comprehensive book for more detailed information. It is worth the price, and comes with a wealth of resources. I know it gave me a lot to think about and even more ideas for projects.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here