[su_note note_color=”#fafafa”]UPDATE: Sitecore Support confirmed it’s a bug in the MVC pipelines in 7.5. If you are doing WebForms you should be fine with mixed case placeholder keys. There’s now a Sitecore.Support.424797.dll
patch that replaces GetAllowedRenderings
with a corrected version. I still believe proper fix belongs in the cache class itself – exposing the knowledge of the cache key semantics and the GetCacheKey()
method logic outside the cash class’s boundaries manifests a leaky abstraction but that’s an off-topic software architecture debate.[/su_note]
Placeholder Settings
We all know and love placeholder settings in Sitecore. If you are new to Sitecore or are not exactly sure what is the difference between global and localized placeholder settings (important for this blog post) I recommend that you read this good article by Chris Castle:
The Power Of Placeholder Settings
Allowed Renderings
Placeholder settings control what renderings (aka components) can be used in a given placeholder on a page. You normally define it on the placeholder settings item (the Allowed Controls
field). In SCORE we also have an extension that allows us to override placeholder settings via declarative rules. One way or the other, you placeholder has to have a placeholder setting that allows at least one control to be inserted into it, otherwise there’s not much you can do with it in Page Editor.
Placeholder Cache
Page Editor uses a special kind of metadata to overlay your pages with its editing features – chrome data (I have blogged about chromes before). Chrome Data is collected via the getChromeData
pipeline that in turn uses getPlaceholderRenderings
to read placeholder settings. Long story short, main processor in that pipeline that is of interest for today’s blog post – GetAllowedRenderings
– does two things:
- Reads your placeholder settings from the item’s layout definition if it’s defined there (localized placeholder setting)
- Searches for a global placeholder setting with a key that matches the placeholder it runs the pipeline for
Prior to 7.5 that second step was a simple query over placeholder settings items in the /sitecore/Layout/Placeholder Settings
. 7.5 introduced a new cache – Placeholder Cache. I guess querying that structure over and over again was identified as a bottleneck and it was decided to cache it. If you inspect the config on a running 7.5 instance you will find six occurrences of the new Sitecore.Caching.Placeholders.PlaceholderCacheManager
that handles keeping the cache up to date upon changes to the items. The cache, of course, initializes itself lazily upon first use.
Case Matters
Do you lowercase your placeholder keys? We normally don’t. I kind of like the mixed case approach: Main
vs. main
, or Above Page Content
vs. above page content
. It reads better I guess. Alas, can’t do it in 7.5 initial release. Not with global placeholder settings.
Placeholder Cache stores placeholder settings items using the Placeholder Key
value as a key. There’s one caveat though. The cache uses a conversion method to calculate the actual cache key from the value that is passed in:
protected virtual string GetCacheKey(string key) { if (this.IsKeyCaseSensitive || string.IsNullOrEmpty(key)) return key; else return key.ToLowerInvariant(); }
Placeholder Cache overrides the IsKeyCaseSensitive
property with:
public override bool IsKeyCaseSensitive { get { return false; } }
That will make the actual cache key use the lowercased Placeholder Key
. It all kind of makes sense, right? Main
and main
should probably be the same thing anyway.
[su_note note_color=”#fafafa”]The problem is, in the 7.5 initial release adding the placeholder settings item to the cache and looking it up by key are not symmetrical operations.[/su_note]
Here’s how a global placeholder settings item is looked up:
PlaceholderCache placeholderCache = PlaceholderCacheManager.GetPlaceholderCache(database.Name); Item obj = placeholderCache[placeholderKey];
The indexer property in the cache does not use the conversion method to calculate the key to use for the lookup. The value goes straight into the TryGetValue
of the inner data structure.
What do we do now?
I filed a support ticket with all the details (#425605). I believe the right way to fix is to make the two operations symmetrical and use the GetCacheKey
when looking up the item from the cache. In the meantime, if you are using 7.5 initial release you are better of with lowercase placeholder keys. And if you are migrating a site from earlier versions to 7.5 you will need to change your renderings to use lowercase keys when referring to a placeholder. You don’t really need to change the Sitecore items but I would do it too. I don’t like asymmetry, especially in placeholder keys.
Thanks Pavel! Ran into this issue working on a 6.6 to 7.5 upgrade. Pulling in the patch took care of it.