Click here to Skip to main content
6,822,123 members and growing! (18,981 online)
Email Password   helpLost your password?
Web Development » ASP.NET » General     Beginner License: The Code Project Open License (CPOL)

ASP.NET Runtime Cache - Clone Objects to Preserve Cached Data (Part II)

By Mark Graham

Part II of protecting cached data with cloning. This article contains more polished code.
C#, .NET, ASP.NET, Dev
Revision:4 (See All)
Posted:27 Nov 2009
Views:2,418
Bookmarked:4 times
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
1 vote for this article.
Popularity: 0.00 Rating: 4.00 out of 5

1

2

3
1 vote, 100.0%
4

5

Introduction

This article is strengthening a previous article I've written, ASP.NET Runtime Cache - Clone Objects to Preserve Cached Data, by presenting you with better code that is available for you to download from this page and use in your applications.

Allow me to re-iterate. My previous article explained that the ASP.NET runtime cache is shared between website requests and that the cache is unprotected, which means that a user can request an object in the cache and then modify the object's data. A second user can make a request for the same cached object and get my modifications, or worse still, half of my modifications.

Pre-Requisites

Knowledge of the ASP.NET technology, an understanding of data caching, an understanding of shallow vs. deep copying, and knowledge of .NET generics is required for this article.

Lock the Cache

One method of resolving this conflict is to introduce locking around the cache, but this can be expensive, certainly when a system is under heavy load. Threads will get blocked, and the OS will be spending more time synchronizing processors and thread-switching, which can be a major bottleneck.

Deep Copy Our Objects

A alternative, and my preference, is to deep copy objects going in and objects coming out. This way, every request reading the cache is getting its own copy of the objects.

Contents of IDeepCloneable.cs
namespace ProtectedCache {

    // Simple interface to indicate intent. I was thinking about using the
    // existing ICloneable interface and documenting it for developers to ensure
    // deep copies are performed. I decided not to and opted for a new self-
    // documenting interface.

    public interface IDeepCloneable {

        object DeepClone();
    }
}
Contents of CacheArgs.cs
using System;
using System.Web.Caching;

namespace ProtectedCache {

    // This is a purely a data object without behavior. It is holding caching
    // expiration data that will be specified when adding to the cache.

    // This may seem pointless or overkill but it does play a huge part in a 
    // RowDataGateway framework (it's a code generated DAL) I have written.
    // I'm not introducing the framework at this stage because I don't want
    // to lose focus and over-complicate this code.

    public sealed class CacheArgs {

        private bool _isCacheable;
        private DateTime _absoluteExpiration = Cache.NoAbsoluteExpiration;
        private TimeSpan _slidingExpiration = Cache.NoSlidingExpiration;        

        public CacheDependency Dependency {
            get {
                return null; // Implement when required
            }
        }

        public DateTime AbsoluteExpiration {
            get { return _absoluteExpiration; }
            set { _absoluteExpiration = value; }
        }

        public TimeSpan SlidingExpiration {
            get { return _slidingExpiration; }
            set { _slidingExpiration = value; }
        }
    }
}
Contents of Cacher.cs
using System;
using System.Web;
using System.Collections.Generic;

namespace ProtectedCache {

    // This is the Cacher; a static helper class that is responsible for
    // performing the deep cloning/copying.

    public static class Cacher {

        public static T Load<t>(string key) where T : IDeepCloneable {
            
            // Perform a thread-safe read of the cache

            object item = HttpRuntime.Cache[key];

            // If the item isn't null and it's type is equal to the
            // type of generic T then cast the item, deep clone it, then
            // return it casted of type generic T, otherwise, return the
            // default of generic T

            if (item != null && (item.GetType() == typeof(T))) {
                return (T)((IDeepCloneable)item).DeepClone();            
            } else {
                return default(T);
            }
        }

        public static void Save<t>(T item, string key, CacheArgs args) where T : 
                                     IDeepCloneable {

            // Insert a deep cloned item in to the cache

            HttpRuntime.Cache.Insert(key, item.DeepClone(), args.Dependency,
                args.AbsoluteExpiration, args.SlidingExpiration);
        }
    }
}

Resources

I try to write when I can, but sometimes it's difficult finding time to complete lengthy articles. However, I do write snippy-snappy posts, providing useful tips and code samples at http://designcodetest.blogspot.com/. Come along, have a read, and please leave feedback.

History

This is the first version of my article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mark Graham


Member
Areas of expertise: c#, asp.net, design patterns, GUI useability/layout
Occupation: Web Developer
Company: Currently working on projects for May Gurney
Location: United Kingdom United Kingdom

Other popular ASP.NET articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
GeneralI have a couple of improvements PinmemberMark Graham0:10 3 Dec '09  
GeneralI received a message but I can't reply to it. Thanks for feedback Paulo - I'm responding by added a new message here...... PinmemberMark Graham5:27 27 Nov '09  
GeneralRe: I received a message but I can't reply to it. Thanks for feedback Paulo - I'm responding by added a new message here...... PinmemberPaulo Zemek6:30 27 Nov '09  
GeneralRe: I received a message but I can't reply to it. Thanks for feedback Paulo - I'm responding by added a new message here...... PinmemberMark Graham13:17 27 Nov '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads.

PermaLink | Privacy | Terms of Use
Last Updated: 27 Nov 2009
Editor: Smitha Vijayan
Copyright 2009 by Mark Graham
Everything else Copyright © CodeProject, 1999-2010
Web18 | Advertise on the Code Project