In MVC, adding a placeholder in the renderings with capital letters will not create any problem when binding any rendering to this placeholder. However, Sitecore will not resolve your Placeholder settings correctly and you will not see the "Add Here" buttons neither the "allowed controls"
To summarise, if you do something like:
@Html.Sitecore().Placeholder("SideColumn")
You will end up withthe SideColumn placeholder not even displayed, even if you add capital letters in the Placeholder Settings:
< getChromeData> < processor type="Sitecore.Pipelines.GetChromeData.Setup, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetChromeData.GetFieldChromeData, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetChromeData.GetWordFieldChromeData, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetChromeData.GetRenderingChromeData, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetChromeData.GetEditFrameChromeData, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetChromeData.GetPlaceholderChromeData, Sitecore.Kernel" /> < /getChromeData>
When following the trail from the GetPlaceholderChromeData you will find that the code is calling another pipeline "GetPlaceHolderRenderings"
GetPlaceholderRenderingsArgs getPlaceholderRenderingsArgs = new GetPlaceholderRenderingsArgs(text, layout, args.Item.Database) { OmitNonEditableRenderings = true }; CorePipeline.Run("getPlaceholderRenderings", getPlaceholderRenderingsArgs);
with the pipeline looking like:
< getPlaceholderRenderings> < processor type="Sitecore.Pipelines.GetPlaceholderRenderings.GetAllowedRenderings, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetPlaceholderRenderings.GetPredefinedRenderings, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetPlaceholderRenderings.RemoveNonEditableRenderings, Sitecore.Kernel" /> < processor type="Sitecore.Pipelines.GetPlaceholderRenderings.GetPlaceholderRenderingsDialogUrl, Sitecore.Kernel" /> < /getPlaceholderRenderings>
Continuing the trail... go to the first processor: GetAllowedRenderings. In there you will find out how the PlaceholderItem is getting retrieved
using (new DeviceSwitcher(args.DeviceId, args.ContentDatabase)) { item = Client.Page.GetPlaceholderItem(args.PlaceholderKey, args.ContentDatabase, args.LayoutDefinition); }
If you look inside this method you will see that those placeholder Item are retrieved from the cache:
PlaceholderCache placeholderCache = PlaceholderCacheManager.GetPlaceholderCache(database.Name); Item item = placeholderCache[placeholderKey]; if (item != null) { return item; } int num = placeholderKey.LastIndexOf('/'); if (num >= 0) { string key = StringUtil.Mid(placeholderKey, num + 1); item = placeholderCache[key]; } return item;
You will note that the placeholderCache.IsKeyCaseSensitive is false, and this return null if you are passing the key as capital letters... So if we look at how the cache is build:
public virtual void Reload() { lock (FieldRelatedItemCache.Lock) { this.itemIDs = new SafeDictionary(); string query = string.Format("{0}//*[@@templateid = '{1}']", this.ItemRoot.Paths.FullPath, this.ItemTemplate); Item[] array = this.Database.SelectItems(query); if (array != null) { Item[] array2 = array; for (int i = 0; i < array2.Length; i++) { Item item = array2[i]; string text = item[this.FieldKey]; if (!string.IsNullOrEmpty(text)) { string cacheKey = this.GetCacheKey(text); if (!this.itemIDs.ContainsKey(cacheKey)) { this.Add(text, item); } } } } } }
with the method GetCacheKey where you can see that if the IsKeyCaseSensitive is false the cache key will be lower case...
protected virtual string GetCacheKey(string key) { if (this.IsKeyCaseSensitive || string.IsNullOrEmpty(key)) { return key; } return key.ToLowerInvariant(); }
Also inside the Add method there is also a call to the GetCacheKey... So
string cacheKey = this.GetCacheKey(key); lock (FieldRelatedItemCache.Lock) { this.itemIDs[cacheKey] = item.ID; }
That means the key is stored as capital Letter if you have define your field in the placeholder settings as capital letter. So what happens where we try to retrieve the item from the cache is that we are passing the Key as Capital letter but it is stored as lower case...
public virtual Item this[string key] { get { Item result; lock (FieldRelatedItemCache.Lock) { ID itemId; if (!this.itemIDs.TryGetValue(key, out itemId)) { result = null; } else { Item item = this.Database.GetItem(itemId, Context.Language, Version.Latest); if (item == null) { this.itemIDs.Remove(key); } result = item; } } return result; } }
So I went around this issue by adding a custom pipeline action on the GetChromeData pipeline to convert the Placeholder Key to Lower Invariant if the Key for the cache manager is not sensitive...
namespace MyProject.Business.Sitecore.Pipelines { public class GetPlaceholderKeyForChromeData : GetPlaceholderChromeData { public override void Process(GetChromeDataArgs args) { if ("placeholder".Equals(args.ChromeType, StringComparison.OrdinalIgnoreCase)) { PlaceholderCache placeholderCache = PlaceholderCacheManager.GetPlaceholderCache(args.Item.Database.Name); if (!placeholderCache.IsKeyCaseSensitive) { string keyString = args.CustomData["placeHolderKey"] as string; args.CustomData["placeHolderKey"] = keyString.ToLowerInvariant(); } } } } }
With the following config patch
< getchromedata> < processor patch:before="processor[@type='Sitecore.Pipelines.GetChromeData.GetPlaceholderChromeData, Sitecore.Kernel']" type="MyProject.Business.Sitecore.Pipelines.GetPlaceholderKeyForChromeData, MyProject.Business"> < /processor> < /getchromedata>
No comments:
Post a Comment