EPiServer  /  CMS October 05, 2009

Working with Dynamic Properties and Page Type Builder

Page Type Builder doesn’t currently support creating dynamic properties. Part of the reason for that is that Page Type Builder, for many scenarios, renders dynamic properties unnecessary. I’ll show you why and how soon.

With that said you can still use Page Type Builder to access the value of dynamic properties in a strongly typed way. In this post I’ll show you how plus a way to achieve almost the same functionality as dynamic properties delivers without using them.

A scenario

Let’s say we have a site with a product catalog. It has four page types: a start page, a product page for displaying a product, a product section page for displaying sub sections of products and a product sub section page for displaying products in a sub section. All of the page types inherit from an abstract base class, BasePageData. A simple class diagram looks like this:

Scenario 

Simplified, the site structure looks like this:

Structure

Each product section and each product sub section can have a weekly special offer which is a XHTML property that will be displayed on all pages in the section. If a sub section has a weekly offer then that will be displayed on the sub section’s page and it’s products. If it doesn’t then the parent section’s weekly offer, if there is one, will be displayed. Looks like a dynamic property will solve this for us perfectly!

Accessing dynamic properties in a strongly typed way

We know that Page Type Builder doesn’t support creating dynamic properties. So, how do we work with them then? Well, we create them in admin mode as we normally would.

CreatingADynamicProperty

Then we add code to the BasePageData class to access it’s value using an overload of the GetPropertyValue extension method that allows us to set it’s usePropertyGetHandler parameter to true, which tells it to include dynamic property values.

public virtual string WeeklyOffer
{
    get
    {
        return this.GetPropertyValue(page => page.WeeklyOffer, true);
    }
}

Et voilà! All of the page types now have a WeeklyOffer property that will access the dynamic property’s value in a strongly typed way. If we really don’t want to create the dynamic property in admin mode we can add some code to global.asax or a HTTP module to do that at start up. I wouldn’t necessarily recommend it, but it’s possible :)

Get the same effect without dynamic properties

There are a couple of problems with dynamic properties. First of all they aren’t exactly intuitive to work with for an editor as they aren’t edited on a page. Secondly the performance isn’t great as accessing it’s values can lead to a lot of recursive calls. Let’s say that the current page is a product and we want to get the weekly offer. Now, if neither the products sub section, it’s parent section or the start page has a weekly offer we will have made three unnecessary calls.

Example1

To address the first problem, and to ensure that all of our properties are declared in code we can use regular, but smart, properties. Again in BasePageData we add a property. This time it looks like this:

[PageTypeProperty]
public virtual string WeeklyOffer
{
    get
    {
        string value = this.GetPropertyValue(page => page.WeeklyOffer);

        if (string.IsNullOrEmpty(value) && ParentLink != null && PageLink.ID != PageReference.StartPage.ID)
            value = ((BasePageData)DataFactory.Instance.GetPage(ParentLink)).WeeklyOffer;

        return value;
    }
}

What we did above was that we declared a regular EPiServer XHTML string property and implemented the corresponding code property in such a way that if the current PageData object doesn’t have a value for this property it will ask it’s parent for it, given of course that the current PageData object isn’t the start page. As long as we access the EPiServer property through the code property we have achieved the same effect as with dynamic properties, only now the property is editable at the same place as all other properties and we where able to declare it in code. One caveat however is that this won’t work with the built in EPiServer web controls as they don’t have a clue about our classes and their properties, only their corresponding page types and EPiServer properties.

Using the above technique we have also gained more control over how the property’s values are accessed and thereby we are able to mitigate the other problem with dynamic properties that I mentioned before, that accessing the value of a dynamic property that doesn’t have a value set will cause recursive calls all the way up to the start page.

Let’s say that we know that if the property doesn’t have a value at the product section level or below no value should be returned. That is, the weekly offer can’t be specified on the start page. With both dynamic properties and our current implementation of the property without using dynamic propertis the start page would still be queried for the value. We can quite easily fix that. Instead of the above solution where we implemented the property on BasePageData we declare an interface, IHasWeeklyOffer:

public interface IHasWeeklyOffer
{
    string WeeklyOffer { get; }
}

Then, we let the Product, ProductCategory and ProductSubCategory classes implement the interface. For Product and ProductSubCategory the implementation is very similar to the one we had previously on BasePageData. This time however we also make sure that the parent implements IHasWeeklyOffer before we cast it and fetch the value from its WeeklyOffer property.

[PageTypeProperty]
public virtual string WeeklyOffer
{
    get
    {
        string value = this.GetPropertyValue(page => page.WeeklyOffer);

        if (string.IsNullOrEmpty(value) && ParentLink != null && PageLink.ID != PageReference.StartPage.ID)
        {
            PageData parent = ((BasePageData) DataFactory.Instance.GetPage(ParentLink));
            if (parent is IHasWeeklyOffer)
                value = ((IHasWeeklyOffer)parent).WeeklyOffer;
        }

        return value;
    }
}

For ProductCategory, which should basically say “Here, but no further”, we just return the value of the property. That is, we implement the WeeklyOffer property like this:

[PageTypeProperty]
public virtual string WeeklyOffer { get; set; }

Compared to our previous implementations the start page will never be asked for the WeeklyOffer property’s value with this solution. It might not mean that much performance wise in this scenario but working with “fake dynamic properties” this way gives us greater control, and in scenarios with a very deep structure it can also be beneficial performance wise.

Example2

PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.

Joel Abrahamsson

Joel Abrahamsson

I'm a passionate web developer and systems architect living in Stockholm, Sweden. I work as CTO for a large media site and enjoy developing with all technologies, especially .NET, Node.js, and ElasticSearch. Read more

Comments

comments powered by Disqus

My book

Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!

More about EPiServer CMS