NEW! Caching templates for web projects.

Posts   
 
    
cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 30-Dec-2004 23:40:56   

http://code.caliberweb.com/Gallery.Caching.zip

Author: Chris Martin Date: 12/30/04

Easy caching of LLBLGen entities v 1.0! An "add-on" to the manager templates.

Now, this will be something I don't think anyone would expect out of Template Studio templates. This code meant for web projects.

It basically does automatic caching and retrieving of object for you. No more fumbling with the cache in every damn page.

There are 3 main types of objects that are important. 1. An ObjectLoader is a delegate to a method that will retrieve your data. An ObjectLoader is created for every Fetch method in the manager classes with the following naming covention: *Loader_[type signature] (ex. public delegate ContactEntity WithArtworksLoader_String(String artistId) ). If the delegate takes zero arguments, there is no underscore in the name.

  1. A CacheInfo object is where you set your Cache expiration, dependencies, etc...

  2. A CacheProxy object is where all the work takes place. They share the same naming convention as the ObjectLoader classes with the word "Loader" being replaced with "CacheProxy". All you have to do is create a proxy with a key, a CacheInfo, the parameters your ObjectLoader needs, and the loader itself. To get your object just call cacheProxy.Value and cast it to whatever type it is.


Installation.

  1. Place the templates in the same folder as the manager templates (TemplateStudio\Drivers\SqlServer\Templates\Gallery).

  2. Replace the Gallery.Core.TemplateSet.config file in "TemplateStudio\Drivers\SqlServer\Templates".

  3. Replace the Gallery.Core.Managers.config in "TemplateStudio\TaskPerformers"


Use

  1. Fire up Template Studio to generate the code.

  2. A couple of new folders will be created. A. Caching B. Caching\ObjectLoaders C. Caching\Proxies

  3. Copy the Caching folder to your project.

  4. Use this code as a starting point: A. In your using section of code add these two lines. 1. using ObjectLoaders = <your-project-namespace>.Core.Caching.ObjectLoaders; 2. using Proxies = <your-project-namespace>.Core.Caching.Proxies; B. In the method that retrieves an *Entity or EntityCollection use this code (of course you will have to use the correct object for your project.)


    string artistId = "ADIX0";

    string cacheKey = string.Format( "Artist{0}Artworks", artistId );
    
    //This is a pointer to the method that retrieves the data from persistent storage.
    ObjectLoaders.Contact.WithArtworksLoader_String loader = new ObjectLoaders.Contact.WithArtworksLoader_String( ContactManager.FetchArtistArtworks );

    //CacheInfo tells the system cache how long to cache and what dependencies.....
    CacheInfo info = new CacheInfo( DateTime.Now.AddMinutes( 1 ) );

    //All of the proxy classes
    //require a key to identify the cached item, a CacheInfo object, and opitionally a Cache object to store objects in.
    //This particular proxy class takes, in addition to a key, a string id, and a delegate pointing to 
    //the method that will retrieve the data from a datastore.
    Proxies.Contact.WithArtworksCacheProxy_String proxy = new Proxies.Contact.WithArtworksCacheProxy_String( cacheKey, info, artistId, loader );

    //Now there is no need to call our data layer at all. Just grab the proxy objects' Value property. The 
    //proxy object takes care of returning the cached item or retrieve the object from the datastore.
    return (ContactEntity)proxy.Value;
    
You can cache any object that the manager classes will fetch. Here's an example of caching an EntityCollection

    ObjectLoaders.Artwork.CollectionLoader l = new ObjectLoaders.Artwork.CollectionLoader( ArtworkManager.FetchCollection );
    Proxies.Artwork.CollectionCacheProxy p = new Proxies.Artwork.CollectionCacheProxy( "", null, l );

    EntityCollection allArtworks = (EntityCollection)p.Value;
    

Afterwords

If anyone has any ideas for better naming conventions, I'm ALL ears. The names can get kinda ugly. But, I personally don't care because of the ease of use.

If anyone extends these, please share.

Otis, I would have put these in your Subversion repo. But, I want them seperate from the manager classes and couldn't come up with a good way to do that and keep the manager classes "virgin" like. wink

Enjoy, Chris

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 31-Dec-2004 11:28:13   

Haven't looked into it in detail, but it looks great! simple_smile

You could create a folder under 'Templates' called ManagersTemplatesExtensions, also with branches, tags and trunk, and store the templates in the Trunk there. If you are unsure how to do that due to unfamiliarity with subversion, I can do that for you, I'll do that this weekend I think

Frans Bouma | Lead developer LLBLGen Pro
cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 08-Jan-2005 11:02:09   

I'm suprised that no one is interested in these templates. I think it's a great pattern for caching.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 08-Jan-2005 11:55:35   

This is not meant to hurt anybody's feelings, but the average developer is not as skilled as a lot of people think. They walk the paths they're told to walk. You offer an advanced set of templates, that takes several steps to make it work: you have to know stuff about these things called templates, what's caching? etc. etc. Often developers think "Ah great!" but don't do anything with it really.

You could check them in into the repository, people who'll look there will see them and probably try them. I can up them to the 3rd party section if you'd like.

Frans Bouma | Lead developer LLBLGen Pro
cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 08-Jan-2005 19:14:16   

Otis wrote:

This is not meant to hurt anybody's feelings, but the average developer is not as skilled as a lot of people think. They walk the paths they're told to walk. You offer an advanced set of templates, that takes several steps to make it work: you have to know stuff about these things called templates, what's caching? etc. etc. Often developers think "Ah great!" but don't do anything with it really.

You could check them in into the repository, people who'll look there will see them and probably try them. I can up them to the 3rd party section if you'd like.

You're welcome to put them anywhere you would like. I'm not really hurt by no one using them. Just surprised wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 09-Jan-2005 12:44:57   

I'll upload them on monday simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 12-Jan-2005 18:26:14   

Otis wrote:

I'll upload them on monday simple_smile

Make that thursday ...

Sorry about that simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 13-Jan-2005 12:03:41   

I've added these templates under a new folder in the repository: ManagerTemplatesAddOns/WebProjectCachingTemplates (which has its own trunk/tags/branches folder set)

I do think it would be better if the current trunk / tags / branches folder set in the manager templates moves to a subfolder in Managertemplates called 'Core' and the addons folder moves to the ManagerTemplates folder as a subfolder. But for now it's ok how it is now.

Frans Bouma | Lead developer LLBLGen Pro
Jeff M
User
Posts: 250
Joined: 04-Aug-2004
# Posted on: 13-Jan-2005 15:35:33   

Chris,

Thanks for these templates. Just downloaded them. I'll feedback after I use them.

Jeff

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 13-Jan-2005 16:57:37   

Right on, these rock. Just in time too. I was about to start writing my caching code for my latest project.

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 14-Jan-2005 23:34:04   

Here is the code that I ended up with. I am using instance specific controllers / manager


            string cacheKey = string.Format("RiskCategoryCollection{0}", Guid.NewGuid(), CultureInfo.InvariantCulture);
            
            ControllerBase controller = 
                ControllerFactory.GetController(ControllerKeys.RiskCategoryControllerKey);
            
            ObjectLoaders.RiskCategory.CollectionLoader collectionLoader = 
                new ObjectLoaders.RiskCategory.CollectionLoader(
                ((RiskCategoryControllerBase)controller).FetchCollection);

            CacheInfo info = new CacheInfo(Cache.NoAbsoluteExpiration, null, 
                TimeSpan.FromMinutes(5), null);

            Proxies.RiskCategory.CollectionCacheProxy proxy = new Proxies.RiskCategory.CollectionCacheProxy(
                cacheKey, info, collectionLoader);

            EntityCollection myCollection = proxy.Value as EntityCollection;

            Assert.IsNotNull(myCollection, "My collection is null");

Which indeed is very cool code. It doesnt work well from nunit because there is no http context, but should work fine from ASP.NET, and thats the next test.

My question is where would a good place for this particular code to be encapsulated at?

Would you reccomend writing a ProblemDomain specific object that could be accessed from various functional areas? Like if my UI deals with customers, orders, and employees, create a class that exposes Customers, Employess, and Orders via properties, where the properties simply return prixy.Value?

cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 16-Jan-2005 02:02:40   

I think that's perfectly fine to abstract them away like you're suggesting. I think I'll work on something like that next. wink

My original, maybe a bit short-sighted, plan was just to use them in a BindData() method in my user controls when I needed them.

I like your idea better. simple_smile

John
User
Posts: 28
Joined: 15-Jan-2005
# Posted on: 19-Jan-2005 14:24:06   

How would one go about making this dependant on a catalogue table, rather than say just expiring every 5 minutes, or making dependant on file?

My existing method would be:

//Create dependency on file CacheDependency dep=new CacheDependency(Server.MapPath("my.xml")); // Add to cache Cache.Insert("Count", 0, dep);

Then when the data was changed in the CMS I would manually change the XML file.

Anyone got any solutions which remove the need to amend the XML file and to just make it dependant on data?

Thanks

Devildog74
User
Posts: 719
Joined: 04-Feb-2004
# Posted on: 19-Jan-2005 16:22:40   

Good question. I was going to ask what would be the best way to dump any cached objects fetched by a proxy when a manager performs a delete or save. That is when I would want to dump the cached object.

cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 20-Jan-2005 05:45:54   

John wrote:

How would one go about making this dependant on a catalogue table, rather than say just expiring every 5 minutes, or making dependant on file?

My existing method would be:

//Create dependency on file CacheDependency dep=new CacheDependency(Server.MapPath("my.xml")); // Add to cache

Cache.Insert("Count", 0, dep);

Then when the data was changed in the CMS I would manually change the XML file.

Anyone got any solutions which remove the need to amend the XML file and to just make it dependant on data?

Thanks

If your catalog table is a file like "my.xml" you can supply that to the CacheInfo object.

There are some work-arounds, that are quite ugly IMO, to use data as a cache dependency floating around for ASP.NET 1.1. However, that is not natively supported by the framework. If you find a method that you like, you're more than welcome to use it with the templates wink .

I would wait until ASP.NET 2.0 to attempt it though.

cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 20-Jan-2005 05:47:11   

Devildog74 wrote:

Good question. I was going to ask what would be the best way to dump any cached objects fetched by a proxy when a manager performs a delete or save. That is when I would want to dump the cached object.

That is a very good question and one that I haven't thought of really. I WILL be thinking of that in the next few days for sure wink

Toddles
User
Posts: 2
Joined: 02-Feb-2005
# Posted on: 02-Feb-2005 10:02:56   

That is a very good question and one that I haven't thought of really. I WILL be thinking of that in the next few days for sure wink

I've just started playing around with these templates a bit and am wondering if a solution to the cache invalidation problem has been created.

cmartinbot
User
Posts: 147
Joined: 08-Jan-2004
# Posted on: 02-Feb-2005 20:25:20   

Toddles wrote:

That is a very good question and one that I haven't thought of really. I WILL be thinking of that in the next few days for sure wink

I've just started playing around with these templates a bit and am wondering if a solution to the cache invalidation problem has been created.

I started to think about it but, haven't come up with a solution just yet. If I find some time here, I can get something worked out.

You can always call Cache.Remove( myCacheKey ) when you need to invalidate an object.

cfwettermark avatar
Posts: 7
Joined: 04-May-2005
# Posted on: 21-Nov-2005 13:15:08   

Hi,

I hope cmartinbot sees this somehow...

I'm fiddling about with the caching templates, which are AWESOME. Clean, slick... you name it.

Just a small question though: how do I go about in caching/fetching a filtered EntityCollection? Basically, what I would want is to be able to specify an overload of FooManager.FetchCollection() which accepts a PredicateBucket as a delegate to the CollectionLoader.

Any tips would be most welcome, and thank you for providing these templates.

CF

Anthony
User
Posts: 155
Joined: 04-Oct-2006
# Posted on: 04-Oct-2006 05:11:36   

Where is the template..interested in using it.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 04-Oct-2006 11:00:13   

in our subversion repository:


svn://www.sd.nl/LLBLGenPro

they're for 1.0.2005.1

Frans Bouma | Lead developer LLBLGen Pro
pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 24-Sep-2007 19:51:16   

Otis wrote:

in our subversion repository:


svn://www.sd.nl/LLBLGenPro

they're for 1.0.2005.1

I would be interested in caching templates. Would these work with LLBLGen 2.5? Or are any other ones available?

Thanks, Patrick

PS: The download above is not available anymore by the way.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 25-Sep-2007 12:49:57   

pat wrote:

Otis wrote:

in our subversion repository:


svn://www.sd.nl/LLBLGenPro

they're for 1.0.2005.1

I would be interested in caching templates. Would these work with LLBLGen 2.5? Or are any other ones available?

It would require template porting, but it wouldn't be that much work I think. Please check the SDK for v2.5 for details about the changed template system (no more .config files but templatebindings files)

PS: The download above is not available anymore by the way.

correct, they're now here (subversion repository: )


svn://www.sd.nl/LLBLGenPro/Templates/ManagerTemplatesAddOns/WebProjectCachingTemplates/Trunk

Frans Bouma | Lead developer LLBLGen Pro