CacheHelper and Secondary Filters

Posted: 4/6/2022 12:54:28 PM by Chris Bass | with 0 comments
Filed under: API, Caching

Been a while since I've posted! For today, I wanted to show off a simple little test case: 

public class GenericWrapper
    public string Title { get; set; }

public GenericWrapper GetTestCase()
    return new GenericWrapper();

public void Test()
    var test = CacheHelper.Cache(cs => GetTestCase(), new CacheSettings(10, "cacheKey")); //First run, will call GetTestCase()
    var testCached = CacheHelper.Cache(cs => GetTestCase(), new CacheSettings(10, "cacheKey")); //Second run, will get the item from Cache.

    CMS.EventLog.EventLogProvider.LogInformation("test0", $"{test.Title}");
    CMS.EventLog.EventLogProvider.LogInformation("testCached0", $"{testCached.Title}");

    test.Title = "TestUpdated";

    CMS.EventLog.EventLogProvider.LogInformation("test1", $"{test.Title}");
    CMS.EventLog.EventLogProvider.LogInformation("testCached1", $"{testCached.Title}");

    testCached.Title = "TestCachedUpdate";

    CMS.EventLog.EventLogProvider.LogInformation("test2", $"{test.Title}");
    CMS.EventLog.EventLogProvider.LogInformation("testCached2", $"{testCached.Title}");


If you saw the above code, what would you expect the Event Log items logged to be, on the first run? After all, the first call gets the GetTestCase() object directly (and caches it), and the second just pulls it from the cache, right? So, since when the cache is called, both items have a blank title, I would've expected each object's Title property should be blank until it's set.

Turns out, in both Kentico 12 and 13 (I haven't tried earlier versions), test and testCached actually point to the exact same object. In other words, CacheHelper isn't deserializing some 'snapshot' copy of the object each time the cache is retrieved, but pulling a reference to the same live object. So as soon as the 'Title' property of either is updated, it's updated for both.

Furthermore, on future requests, the "Cached" value of 'blank Title' is *not* what is returned by CacheHelper, but rather "TestCachedUpdate", a value we probably never expected to be cached!

Which is all to say, if you ever have to modify properties of an object coming back from CacheHelper, export them first. For example, if your object has an "Items" list, copy those Items out to another list and modify *that* one, don't just add/remove items from your Items list, because if you do you're essentially directly modifying the Cache.

Blog post currently doesn't have any comments.
 Security code