Strongly typed property access and page type inheritance - again

by: Joel Abrahamsson

There has been quite a lot of talk about strongly typed property access lately. There has also been a few very interesting blog posts about how to achieve both strongly typed property access and page type inheritance. Fredrik Tjärnberg has developed a Visual Studio plugin first described here and later here. Daniel Rodin and Mikael Nordberg has described another solution here and here.

And yes, here’s yet another solution. It is actually very similar to the one that Daniel Rodin and Mikael Nordberg described. As I found their solution very interesting but couldn’t find any downloadable source code attached to their blog entries, and as I also so an opportunity to utilize the new features in R2 Sp2 RC that Fredrik Tjärnberg described in his second blog entry about his Page Type Tool, I decided to write my own.

You are very much welcome to download the source code, as well as the resulting assembly, from here. Please do keep in mind that at this stage it’s just an experiment. Quite a lot of work remains to be done and the whole idea needs to be tested more before I can even be sure it’s viable.

How to use it – A hello world

The hello world of using this tool is referencing the assembly (PageTypeBuilder.dll), creating a new class that inherits from PageData with a PageTypeDefinition attribute and making a request to the site. This will create a new page type with the name of the newly created class.

Allow me to illustrate. We begin by referencing the PageTypeBuilder assembly, or the project, in a EPiServer web project. We then create a new class like this:

using EPiServer.Core;
using PageTypeBuilder;
 
namespace SP2RC.PageTypes
{
    [PageTypeDefinition]
    public class MyPageType : PageData
    {
    }
}

imageFinally we compile the project and head on over to EPiServers admin mode where we find that a new page type has been created.

image

The settings for sort index and availability in edit mode is set to the default values. The file name is also set to a default value. That one is however not set by the CMS but by the page builder tool and we can easily change it by modifying the PageTypeDefinition attribute. The attribute also allows us to specify a name for the page type other than the class name. It might look something like this:

[PageTypeDefinition(Filename = "/MyPageTemplate.aspx", 
    Name="MyVeryOwnPageType")]
public class MyPageType : PageData
{
}

Specifying the file name will only result in the file name property of the page type being updated. Specifying a different name for the page type will however lead to a new page type being created, and the old one won’t get removed. I have some ideas on how to handle this better in the future but would very much like to hear ideas and opinions about this subject.

Specifying properties

We can add a property to our page type by creating a new property in the class and adding a PropertyDefinition attribute to it.

[PageTypeDefinition]
public class MyPageType : PageData
{
    [PropertyDefinition]
    public string MainBody { get; set; }
}

This will result in a new XHtml property being added to the page type.

image

Let’s also add a headline. We want that to be a string but on the page type we don’t want it to be a XHtml string (what the tool defaults to for strings) but a short string. We accomplish that by specifying that it should be a PropertyString by setting the PropertyDefinition’s Type property.

[PropertyDefinition(Type = typeof(PropertyString))]
public string Headline { get; set; }

The result will look like this:

image

The PropertyDefinition attribute also allows us to specify which tab the property should be placed under (it will default to the first one), the edit caption (it will default to the property name) and the help text.

How to handle sort order, default values etc is another thing I’d love some input on.

Implementing the property data access

The properties that we just created in our page type class results in properties being added to the page type, but they won’t actually retrieve or store values.  We could implement the properties like this:

[PropertyDefinition(Type = typeof(PropertyString))]
public string Headline
{
    get
    {
        return GetValue("Headline") as string;
    }
    set
    {
        this["Headline"] =value;
    }
}

The above code would work fine but it looks a bit nasty. Luckily there’s a class in the PageTypeBuilder assembly called PropertyValueUtility which adds two extension methods to the PageData class and it’s descendants, GetPropertyValue and SetPropertyValue. These two will look quite familiar to anyone who has read Daniel Rodins blog entry. They have really come up with a smart solution. Hats off!

By using the two extension methods we can implement the properties like this:

[PropertyDefinition(Type = typeof(PropertyString))]
public string Headline
{
    get
    {
        return this.GetPropertyValue<MyPageType, string>(
            page => page.Headline);
    }
    set
    {
        this.SetPropertyValue<MyPageType, string>(
            page => page.Headline, value);
    }
}
 
[PropertyDefinition]
public string MainBody 
{
    get
    {
        return this.GetPropertyValue<MyPageType, string>(
            page => page.MainBody);
    }
    set
    {
        this.SetPropertyValue<MyPageType, string>(
            page => page.MainBody, value);
    }
}

While we might loose a little readability the implementation is now strongly typed.

Using the page type

By inheriting from the new TypedPageBase class in R2 SP2 using the page type class is a joy. We inherit from TypedPageBase<MyPageType> and can then access our properties in a strongly typed way by getting the current page object, as a MyPageType, from the (new) CurrentTypedPage property.

public partial class MyPageTemplate : TypedPageBase<MyPageType>
{
    protected void Page_Load(object sender, EventArgs e)
    {
        LiteralHeadline.Text = CurrentTypedPage.Headline;
        LiteralMainBody.Text = CurrentTypedPage.MainBody;
    }
}

We could also retrieve an instance of our page type class by using the new generic GetPage method in Datafactory:

DataFactory.Instance.GetPage<MyPageType>(aPageReference);

Source code and request for feedback

The source code for the PageTypeBuilder can be downloaded here. Remenber that you will need to EPiServer CMS R2 SP2 RC or higher to fully be able to use it.

Any feedback and ideas for improvement are very, very welcome. Please keep in mind however that this is just a little weekend project so far and should be considered an experiment :)

01 June 2009


Comments

  1. Sweet implementation, this is looking really nice!
  2. Nice! That'll stop us having to synchronise our code with our page type definitions. :)
  3. Good one! From no options in this area to multiple options in just a couple of months. Amazing!. I'm glad that you liked the generic additions to DataFactory. It's definitely a plus that your approach is tool agnostic something the Page Type Tool is not (per definition ;) ). Both our solutions have issues with maintaining page types even though the "namespace approach" when naming page types in the Page Type Tool makes it possible to automatically clean up "obsoleted" page types. To boost the developer productivity in your solution a VS CodeSnippet would do wonders (a'la dependency properties of WPF and WF). Looking forward to see more of this.
  4. Nice! Another feature could be a report which properties and pages are not used anymore. Garbage properties can be a problem further along the development life cycle and it would be nice to which properties isn't part of the typed property framework.
  5. Indeed! Something like that is actually a planned feature, though it might have to wait until version 1.5 or something like that :) Just so you know, there has been a few releases after this blog post was written, which can be found at http://pagetypebuilder.codeplex.com/.
  6. Hi! Whatever happened to the generic TypedPageBase class? It was there in the RC, but seems to be removed in the shipped version of SP2. How are you supposed to access your typed properties now when you cannot inherit from TypedPageBase ?
  7. Hi! It was removed in the real release of SP2. You can create a base class for pages and controls that has a property that retrieves the CurrentPage in a strongly typed way. I will also add such classes in version 0.8.
  8. Thanks for the quick response, I wrote a custom base class for now. Looking forward to the next release of PageTypeBuilder, this is something I have been waiting for for years. :-)
  9. Glad to hear that! Make sure you bookmark http://pagetypebuilder.codeplex.com/ for the latest version ;)
  10. Thanks for your article. Have you noticed how many online Tennessee Titans Jerseys articles are boring rehash that leave you feeling like you want the 5 minutes it took to read each one back? Me too. Well, there's a reason why writing a good Minnesota Twins Jerseys article has become a lost art: chasing the almighty dollar. Website owners are looking for ways to get free traffic, and writing lots of Pittsburgh Penguins Jerseys articles with links in them has become one of the preferred methods. Look around and you'll find plenty of 'gurus' out there claiming they can teach you to write 20 Calgary Flames Jerseys articles a day so you can "dominate your competition." This is all well and good. I'd never begrudge someone their drive to earn a living online. But in the process of clamoring to write tons of Miami Heat Jerseys articles and saturate the Web.
  11. When the history of the 2011 http://www.nfljerseyhot.com/Customized_NFL_Jersey.html Customized NFL jersey lockout is written (though we're not sure just who on Earth would want to read it), the date May 24 will not go down as one in which the http://www.nfljerseyhot.com/Donald_Driver_Jerseys.html GDonald Driver Jersey league won the hearts and minds of the football-loving populace.
  12. Hugging each one of your toes like a glove, [url=http://www.fivefinger-vibram.biz]Vibram Five Fingers[/url] is the most innovative footwear choice on the market. Radically readdressing how footwear can be worn, the revolutionary shoe is specially designed so that the wearer has the impression of walking barefoot yet remains protected and safe.
Post a comment    
User verification Image for user verification  
EPiTrace logger