Caching multiple output versions of pages: custom key variable

Tobias Beckendorff asked on February 27, 2019 11:18

Hello,

we use output cache on a Kentico 11 portal engine site. We have set Output cache variables "sitename" and "lang".

There is a new requirement coming in. Basically some content needs to be customized based on a custom cookie. The current plan is to deliver the content through a custom web part or such.

Is there a way to introduce a custom output cache key variable (in our case the custom cookie) to store multiple versions of a page?

The only alternative seems to be to write a very complicated substitution macro, which I think is not meant for more than something like a timestamp ect.

Any suggestions appreciated.

Regards, Tobias

Recent Answers


Michal Samuhel answered on February 27, 2019 13:27

How about trying to leverage: GetVaryByCustomString event in application events ? In Kentico we override default Microsoft method and add in an event that allows you to hook onto it and inject extra variables.

0 votesVote for this answer Mark as a Correct answer

Tobias Beckendorff answered on February 28, 2019 11:00

Hi Michal,

Could you elaborate on that? I don't get the GetVaryByCustomString event to fire.

0 votesVote for this answer Mark as a Correct answer

Michal Samuhel answered on February 28, 2019 18:38

GetVaryByCustomString fires when application requests custom string key for output caching and we are adding to it via our own override:

// Get base value var result = base.GetVaryByCustomString(context, custom);

        var e = new GetVaryByCustomStringEventArgs
            {
                Context = context,
                Custom = custom,
                Result = result
            };

        return CMSApplication.GetVaryByCustomString(e);

Then we are using result of raised event in further processing of output in OutputHelper.GetVaryByCustomString.

So you could change it and override on your own it on application level in GlobalAsax and I am not sure whether this would not require a touch in customization of CacheHelper as well. Another approach would be following web.config key CMSOutputCacheItems where comma separate values can be entered, but that will not help with cookie based recognition as config is not dynamic enough.

Another suggestion, that I am thinking is to create custom Helper and override GetVaryByCustomString, but be careful, since this helper does a lot of heavy lifting and work to retrieve items properly.

0 votesVote for this answer Mark as a Correct answer

Tobias Beckendorff answered on March 1, 2019 11:09

Hi Michal,

I think I haven't been clear on the requirement:

Out of curiosity I set up a page with partial caching for a webpart - now the event is fired.

However, it is modifying keys for full page output caching I am interested in.

Is there a similar approach for this situation?

Thanks, Tobi

0 votesVote for this answer Mark as a Correct answer

Michal Samuhel answered on March 8, 2019 12:23

Hi Tobias,

I had found out another, better approach (though cache variables should still work). Anyway,

private void OutputFilter_SaveOutputToCache_Before(object sender, OutputCacheEventArgs e)
        {

string cacheKey = e.Output.CacheKey;

//var cookieKey = HttpContext.Current.Request.Cookies["cache"];

cacheKey = cacheKey + "|Test";

e.Output.CacheKey = cacheKey;
}

Will allow you to change cache keys with which item is stored. However, you will also have to connect to additional SendCacheOutput event where you are passed output variable by reference and you can use TryGetFromCacheInternal according to your custom keys.

Hope this works for you now.

0 votesVote for this answer Mark as a Correct answer

Tobias Beckendorff answered on March 12, 2019 10:39

Hi Michal,

I don't think that works either. The limitation is the SendCacheOutput: "Occurs only if the cached output is found...". Because the system checks only the default cache keys nothing is found for the manipulated key.

I found a solution which works for me by implementing custom CacheHelper and overriding GetInternal and InsertInternal Methods:

[assembly: RegisterCustomHelper(typeof(CustomCacheHelper))]
public class CustomCacheHelper : CacheHelper
{

    protected override object GetInternal(string key, bool useFullKey)
    {
        if(key.StartsWith("outputdata"))
        {
            string cookieValue = this.GetCustomCookieValue();
            if(!String.IsNullOrEmpty(cookieValue))
            {
                key += "|myKey=" + cookieValue;
            }           
        }
        return base.GetInternal(key, useFullKey);
    }

    protected override void InsertInternal(string key, object value, CMSCacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback, bool useFullKey)
    {
        if (key.StartsWith("outputdata"))
        {
            string cookieValue = this.GetCustomCookieValue();
            if (!String.IsNullOrEmpty(cookieValue))
            {
                key += "|myKey=" + cookieValue;
            }
        }
        base.InsertInternal(key, value, dependencies, absoluteExpiration, slidingExpiration, priority, onRemoveCallback, useFullKey);
    }
}

I am not fully satisfied with the solution because of the direct key string manipulation, but nothing else seems to be working.

Still thank you Michal, your ideas put me on the right track.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.