Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at
Practical Implementation - spending some cache.

Take a look at my previous post for the details on a cache helper method that I like to use.  In this post, we'll be putting it to work (the word for today is J - O - B).  Here's a look at the code for reference.

using System; using System.Reflection; using System.Web; using System.Web.Caching; using log4net; namespace CacheManagement { public delegate bool Factory<T>( out T instance ); public class CacheHelper { private static readonly ILog log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType ); private static readonly Cache cache = HttpRuntime.Cache; private CacheHelper() { } public static T GetFromCache<T>( string key, int cacheTimeInMinutes, Factory<T> retrieveMethod ) where T : class { T target = cache[key] as T; if ( target == null ) { log.Info( "Cache miss for key:" + key + " type:" + typeof( T ) ); if ( retrieveMethod( out target ) ) { cache.Insert( key, target, null, DateTime.Now.AddMinutes( cacheTimeInMinutes ), Cache.NoSlidingExpiration, CacheItemPriority.Normal, OnRemove ); } } else { log.Info( "Cache hit for key:" + key + " type:" + typeof( T ) ); } return target; } public static void OnRemove( string key, object cacheItem, CacheItemRemovedReason reason ) { log.Info( "Object removed from cache: Key-" + key + ": Reason-" + reason ); } } }

Enter the ASP.NET AJAX AutoComplete Extender.  It's a perfect candidate for a little cache help.  I certainly wouldn't want the database being hit every time a user typed the next letter in the autocomplete box.  I apologize for wearing you down with all this talk.  I think I've said too much.  Let's look at the code for autocomplete webservice.

using log4net; using System.Reflection; using System.Web.Services; using System.Collections.Generic; using CacheManagement; [WebService( Namespace = "" )] [WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 )] [System.Web.Script.Services.ScriptService] public class AutoCompleteWebService : WebService { private static readonly ILog log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType ); private static readonly int cacheTTL = 15; private static readonly int minimumPrefixLength = 3; public AutoCompleteWebService() { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] public string[] GetWordList( string prefixText, int count ) { //minimumPrefixLength should never be greater than prefixText.Length //this is a sanity check to insure the minimumPrefixLength field was set corretly string prefixKey = prefixText.Substring( 0, minimumPrefixLength > prefixText.Length ? prefixText.Length : minimumPrefixLength ); //get the working list List<string> searchList = CacheHelper.GetFromCache<List<string>>( prefixKey, cacheTTL, delegate( out List<string> instance ) { return DataAccess.GetWordList( prefixKey, out instance ); } ); log.Debug( "searchList full count: " + searchList.Count ); //narrow the results if the prefixText is longer than prefixKey if ( prefixText.Length > prefixKey.Length ) { searchList = searchList.FindAll( delegate( string s ) { return s.Substring( 0, prefixText.Length > s.Length ? s.Length : prefixText.Length ) == prefixText; } ); } //only return at maximum the number of results requested by count if ( searchList.Count > count ) searchList = searchList.GetRange( 0, count ); return searchList.ToArray(); } }

The webservice takes the first part of the prefixText (minimumPrefixLength should match the value in the autocomplete extender control) and queries the database for all matches.  It stores that result set in cache and then filters the list by prefixText if needed.  Finally it will take the top X (count is specified by the control) and return it to the control.

If a user was searching for "automobile", after typing a-u-t all possible results would be cache so that each successive letter will not hit the database.  Another database hit will be incurred when a user searches for a different 3 letter prefix. 

I'm attaching the full sample code along with a Sql Express database that contains some huge word list I found online (to be attached later, technical difficulties).  Enjoy and try not to spend it all in one place.

Posted 03-17-2008 8:35 PM by anortham


Comments wrote Practical Implementation - spending some cache.
on 03-24-2008 9:02 AM

You've been kicked (a good thing) - Trackback from

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Google Reader or Homepage Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of
Red-Gate Tools For SQL and .NET


SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
NHibernate Profiler
Balsamiq Mockups
JetBrains - ReSharper
Web Sequence Diagrams
Ducksboard<-- NEW Friend!


Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers


Community Server (Commercial Edition)