EPiServer Composer page is missing a Shadowpage, or a reason why you can’t create functions

by Fredrik Karlsson 22. March 2010 21:10

The problem

You drag a function onto your EPiServer composer page:
Drag

You drop the function in a content area and watch the spinning effect:
drop

The function just disappear!
Missing

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.

Tags: , , ,

Development

Beta release - Calculate your publishing power

by Fredrik Karlsson 27. January 2010 10:49

This is a part in a release by Dropit's section for measurement and Continuous Improvement, Mark Red, and their latest project to calculate yor publishing power.

Publishing Power?

Do you have a creeping feeling that you spent a lot of time to update the site without giving anything back? What gives updates to the Web back in the form of visitors and revenue?
Calculate the "publishing power" of each section of the site by "Pageviews of Section / Work in the Section". Publishing power indicates how much the requests you receive in relation to the time the editors devote to managing content. A high publication power indicates that the section get many visits with little effort.

Of course it is even more interesting to see how much revenue the workload is resulting in. If you use Google Analytics, you can calculate the publishing poser by "$-index for Section / Work for the Section".
If you have a site that is configured to measure income from e-commerce you'll find $-index for the site's sections in the report "Content Drilldown".
Read the entire post at Mark Reds blog

 EPiServer CMS integration

This is a very early release, so all there is right now is a property and a report. The property calculates the time you spend editing a single page and the report displays the accumelated time for a section of the web site.

TimerProperty


The porperty is simply a hidden text field and a javascript function adds time.

Publishing power Report 

The report simply displays the amount of time spent editing a section (current page and all children) of the web site.

Future development

The first thing to add is the integration with Google Analytics. We need to display the page views so we can display the Publishing Power values. And as soon as EPiServer CMS 6 is released, we can use the Page objects to store the information. Lots and lots of a more elegant design!

After that, We're not quite sure. Any suggestions?

Source Code

This is a beta, the entire project is avalible here:
PublishingPower.rar (2.80 mb)

Tags: , , ,

Development

Developer lunch - "From good to great developer - why does it matters and how can we achieve it"

by Fredrik Karlsson 24. January 2010 22:44

For this weeks developer lunch I thought I would pick a seminar I saw at TechDays 2009 here in Sweden.

It was "From good to great developer - why does it matters and how can we achieve it" by Chris Hedgate. Unfortunately, the recording only displayed the screen and not him and since the presentation relied on the audience being able to see him, I had to find another recoring. Luckily, I found pretty much the same presentation from JFokus, and this time they included Chris as well, success. See the movie here.

Tags: , ,

Development

Whats new in EPiServer CMS 6 RC 1 GUI

by Fredrik Karlsson 17. December 2009 15:59

This is a walkthrough of whats new in the EPiServer CMS 6 RC 1 EMVP Christmas Special release. It will focus on UI function changes, since I haven't had the time to look to much at the API.

 View mode/public templates

The only thing changed here is the RCA with new icons:

Top menu

The top menu is updated:

The eye leads to view mode, the question mark is help and the rest is the same.

Dashboard

A couple of new gadgets/icons added:

When enetering for the first time, no gadgets are added:

And the added gadgets/settings are stored after a recompile now! Hooray!

 Edit mode

 Not much have changed here. 

WYSIWYG Editor

By default, Tiny MCE is used.

XForms

You can edit an XForm in Chrome atleast.

Admin mode

Nothing new in UI function design:

Drag and Drop of properties

You can now drag and drop any property on a page type in the admin mode.

Anything else?

Have I missed anything? Want better pictures? Post a comment.

Tags: , , ,

Design

Add a group to all EPiServer Composer function types

by Fredrik Karlsson 17. December 2009 10:23
This little web form allow you to add a group to all EPiServer Composer function types. Very handy if you need to add a new group to all functions.

Use the app

Simply choose the group you want to add and click the button.

Code

Simply download the file and remove the .txt extension.

AddGroupToComposerFfunctiontypes.aspx.txt (4.42 kb)

Tags: , ,

Development

Determining whether an EPiServer page is created by import or not

by Fredrik Karlsson 19. November 2009 13:30

This is one of the hidden gems in EPiServer CMS. It basicly allows you to determine if the page is being created by an import (export/import, mirroring) or not (manually, by code). It is done by checking the CurrentITransferContext in your event. We had this problem in Composer and really had some dirty workarounds for it until we had the oppertunity to talk to MagnusS about it and he showed us the way.

Code

public class Global : EPiServer.Global
	{
		protected void Application_Start(Object sender, EventArgs e)
		{
            XFormControl.ControlSetup += new EventHandler(XForm_ControlSetup);
			EPiServer.DataFactory.Instance.SavingPage += new PageEventHandler(Instance_SavingPage);
        }

		void Instance_SavingPage(object sender, PageEventArgs e)
		{
			if (e.Page == null) return;
			// If it is null, then this is not an import. If it is an object, it is IMPORTING
			if (EPiServer.BaseLibrary.Context.Current["CurrentITransferContext"] != null)
			{
				// We are creating the page by import
				e.Page.PageName += " [created by import]";

			}
		}

Outcome

If you import a page now, it will have " [created by import]" after the pagename.

Tags: ,

Development

Error search an EPiServer Composer function when drag and drop fails

by Fredrik Karlsson 11. November 2009 22:19

One of the most annoying things about EPiServer Composer is its lack of error handling by default. If you have an function that throws an normal .net error message it will not show up as you want it to when you drag and drop a function onto a page. Heres an example.

The Function

This function simply throws an "Divide by zero" error.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Dropit.Extension.Core;

namespace EPiServer.ComposerSampleTemplates.Composer.Functions
{
	public partial class ErrorFunction : BaseContentFunction
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			var i = 0;
			var j = 1/i;			
		}
	}
}

The result

Heres what it will look like in the UI:


and the log file will be empty cause its a normal .net error message.

The tool

This is a simple web form that allows you to see any result generated by EPiServer Composer when trying to load the function. It will display any errors. See image:

The code

You can download it here:

ComposerFunctionsTestPage.rar (821.00 bytes)

Tags: , ,

Development

Recorded seminars from "EPiServer Meetup, Stockholm"'s october meeting

by Fredrik Karlsson 30. October 2009 10:21

The 22 of october, "EPiServer Meetup. Stockholm" held their third meeting. This time the meeting was hosted by Dropit and we recorded all the seminars. The seminars are in swedish, so all you who don't speak swedish probably won't understand a thing.

More...

Tags: ,

Communication | Development

Working with different view modes in EPiServer Composer

by Fredrik Karlsson 14. October 2009 21:23

Introduction

When building a function in EPiServer Composer, there might be times when you have different behaviour in edit mode and in view mode. This article will demonstrate how to determine what view mode you are in.

What is a view mode

View modes is simply composers way of determining if you are, for example editing or viewing a page. If you are editing a page, then Composer will attach all necessary code to be able to drag/drop and edit the function, but if you are viewing the page, then Composer won't add anything.
There are 6 different view modes, see them all with descriptions in the Composer SDK about view modes.

Implementation

The current view mode is displayed in the query string, parameter DE_VM. (DE_VM stands for DropitExtension_ViewMode.) Each view mode has a value assigned to it:

  • ExtensionUndefinedMode = 0
  • ExtensionNormalMode = 1
  • ExtensionAdminMode = 2
  • ExtensionEditMode = 4
  • ExtensionEditOnPageMode = 8
  • ExtensionSpecificVersionViewMode = 16
  • So a request to the url http://exampe.com/default.aspx?id=3&DE_VM=4 will show the page in "Composer - edit on page" mode (if you have enough access rights, that is).

    Determining the view mode

    BaseContentFunction.ViewMode


    A very fast way. You simply get back an Enum-value on wich view mode you are in.

    public partial class MyFunction : Dropit.Extension.Core.BaseContentFunction
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (this.ViewMode == ExtensionGeneric.ViewMode.ExtensionEditOnPageMode)
            {
                // do stuff
            }
            else if (this.ViewMode == ExtensionGeneric.ViewMode.ExtensionNormalMode)
            {
                // Do other stuff
            }
        }
    }
    

    BaseContentFunction.IsEditMode

    A helper function, it simply checks if the view mode is ExtensionEditMode or ExtensionEditOnPageMode.

    public partial class MyFunction : Dropit.Extension.Core.BaseContentFunction
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (this.IsEditMode)
            {
                // do stuff
            }
            else
            {
                // Do other stuff
            }
        }
    }
    

    Dropit.Extension.Common.Utils.GetViewMode( System.Web.HttpContext context )

    This is a way to get the view mode in any other context. Simply pass the context to the method and you will recieve the ViewMode

    public partial class MyFunction : Dropit.Extension.Core.BaseContentFunction
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Dropit.Extension.Common.Utils.GetViewMode( this.Context) == ExtensionGeneric.ViewMode.ExtensionEditOnPageMode)
            {
                // do stuff
            }
            else
            {
                // Do other stuff
            }
        }
    }
    

    Tags: , , ,

    Development

    Developer lunch with recorded seminars

    by Fredrik Karlsson 8. October 2009 11:41

    Starting today, every thursday will be seminar lunch at Dropit. Each week one developer will be in charge of selecting a recorded seminar about something they really like. It could be anything from a presentation of C# 4 to JQuery to an discussion about BDD.

    Each seminar will also be presented here at the blog by the person who picked it, so that you can be inspired too :-)

    Tags:

    Communication | Development

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-Share Alike 2.5 Sweden License.


    Welcome to the Dropit blog!

    Here we, the people that work at Dropit, will write about stuff that interests us. For example web development, especially with .NET and EPiServer - but we'll also talk about other techniques that interest us, marketing on the web, social phenomenons, pop culture, games and software development in general.