The problem
You drag a function onto your EPiServer composer page:
You drop the function in a content area and watch the spinning effect:
The function just disappear!
Some background
As you probably know, each Composer page is actually a lot of EPiServer pages. Each function is an EPiServer page and each Function type is a EPiServer pagetype. So when you create a new function, you actually creates a new EPiServer page. That page is created in the EPiServer tree under a special page called a Shadow page. The shadow page is a container for each composer page and exists in order to make sure that all composer functions are not created on the same level, since that would have a serious performance impact.
Some debugging
The best way to start is to enable logging in Composer and you will probably see something like this:
2010-03-22 20:35:42,022 [23] ERROR Dropit.Extension.UI.Edit.CreateContentFunction [(null)] - Dropit.Extension.UI.Edit.CreateContentFunction: Page 737 was not found
EPiServer.Core.PageNotFoundException: Page 737 was not found
at EPiServer.DataAccess.PageLoadDB.LoadPageInternal(PageReference pageLink, Int32 languageBranchId, IDataReader reader)
at EPiServer.DataAccess.PageLoadDB.<>c__DisplayClass1.b__0()
at EPiServer.DataAccess.DataAccessBase.<>c__DisplayClass1`1.b__0()
at EPiServer.DataAccess.DatabaseFactory.Execute[TResult](Action`1 method)
at EPiServer.DataAccess.DataAccessBase.Execute[TResult](Action`1 action)
at EPiServer.Core.PageProviderBase.<>c__DisplayClass4.b__3()
at EPiServer.Core.OptimisticCache`1.Read(String cacheKey, ReadAndCacheObject`1 readAndCacheObject)
at EPiServer.Core.PageProviderBase.GetPageInternal(PageReference pageLink, ILanguageSelector selector)
at EPiServer.Core.PageProviderBase.GetPage(PageReference pageLink, ILanguageSelector selector)
at EPiServer.DataFactory.GetPage(PageReference pageLink, ILanguageSelector selector)
at EPiServer.Core.PageLanguageSettingsTree.GetClosestSetting(PageReference pageLink)
at EPiServer.Core.PageLanguageSettingsTree.Get(PageReference pageLink)
at EPiServer.Core.PageLanguageSettingsTree.Get(PageReference pageLink, String languageBranch)
at EPiServer.Core.LanguageSelector.LoadLanguage(LanguageSelectorContext context)
at EPiServer.Core.CreatePageData.DefaultPageDataLanguage(Int32 pageTypeID, PageReference parentPageLink, ILanguageSelector selector, IList`1 existingLanguages)
at EPiServer.Core.PageProviderBase.GetDefaultPageData(PageReference parentPageLink, Int32 pageTypeID, ILanguageSelector selector)
at EPiServer.DataFactory.GetDefaultPageData(PageReference parentPageLink, Int32 pageTypeID, ILanguageSelector selector)
at Dropit.Extension.Controllers.ContentFunctionDataManager.CreateContentFunctionData(PageReference extensionPageLink, Int32 contentFunctionTypeId, AccessLevel accessLevel)
at Dropit.Extension.Controllers.ContentFunctionDataManager.CreateContentFunctionData(PageReference extensionPageLink, Int32 contentFunctionTypeId)
at Dropit.Extension.Core.ContentFunctionData.Create(PageReference extensionPageLink, Int32 functionTypeId)
at Dropit.Extension.UI.Edit.CreateContentFunction.Page_Load(Object sender, EventArgs e)
Ok, so page 737 is missing. A liitle bit up in the log file, we see this:
2010-03-22 20:35:41,960 [23] INFO Dropit.Extension.Core.Serializer [(null)] - Dropit.Extension.Core.Serializer: <?xml version="1.0" encoding="utf-8"?>
<specializedextensionpagedata>
<pagestructure shadowguid="06ad9f3b-ea46-414a-b45d-198b03817a5b"
guid="59b27f7d-c2dc-4a06-8251-2bb83e1967e9"
remotesite=""
wid="3326"
pid="2171"
sid="737">
<ca id="SideContent" desc="SideContent content" />
<ca id="TopContent" desc="The top content area" />
<ca id="MainTopContent" desc="The main content top area" />
<ca id="MainBottomContent" desc="The main content bottom area" />
<ca id="SecondaryContent" desc="Secondary content" />
<ca id="BottomContent" desc="The bottom content area" />
</pagestructure>
<content><!-- Empty -->
</specializedextensionpagedata>
As you can see, the sid attribute has the value 737. Sid stands for Shadow ID, or the page that will work as a shadow page for this composer page. And it is missing!
The fix
Just run this code to fix this:
var extensionpagetypes = Dropit.Extension.Global.ListExtensionPageTypes();
var pages = EPiServer.DataFactory.Instance.GetDescendents(PageReference.RootPage);
var composerpages = from p in pages
from pt in extensionpagetypes
where EPiServer.DataFactory.Instance.GetPage(p).PageTypeID == pt.ID // 10610
select EPiServer.DataFactory.Instance.GetPage(p);
PageReference newShadowPage;
PageReference existingShadowPage;
foreach (var composerPage in composerpages)
{
var composerPageData = Dropit.Extension.Core.ExtensionPageData.Load(composerPage.PageLink);
// This is always true, bug in composer?
//if (composerPageData.ShadowPageLink == PageReference.EmptyReference)
if (composerPageData != null)
{
try
{
existingShadowPage = new PageReference(composerPageData.ShadowPageID);
GetPage(existingShadowPage);
}
catch (PageNotFoundException ex)
{
// The shadowpage is missing
// Lets create it
newShadowPage = Dropit.Extension.Controllers.ShadowPageManager.Instance.NewShadowPage(composerPageData.PageLink);
Dropit.Extension.Controllers.PageDataManager.UpdateShadowPageID(composerPage, newShadowPage);
}
catch (Exception)
{
// Something else is wrong
// Lets skip it...
}
}
}
Why is this necessary?
Former versions of Composer had a bug when you copied a composer page. It didn’t generate a new shadowpage for the new page. And when you deleted the old page, the shadow page was deleted as well, simply leaving the newly copied page without a shadow page.