Strongly typed property access - Part one

by: Daniel Rodin

This is a way of mapping EPiServer properties so they can be accessed with strongly typed C# code. This allows for safer code and easy refactoring.  

The normal procedure of accessing properties in EPiServer is done by specifying a string as the propertyname something like this.

   1: pageData.Property.Get("myproperty") 

The problem is that any given propertyname, no matter if it really exists or not will pass without raising a compiler error, and if not a runtime exception will be thrown. For the same reasons refactoring is not a very delightful task either.

Would it not be great if the compiler could tell us if we typed a property that does not exist or by mistake typed a bad name? Or how about having intellisense handing us the available properties directly? Actually, there is a way to get all this.

Mapping the properties

A pagetypes properties is mapped to a C# class like this.

   1: public class MyPageProperties : PropertiesBase
   2: {
   3:     public PropertyString MainIntro { get; set; }
   4:     public PropertyXhtmlString MainBody { get; set; }
   5: }

The base class PropertiesBase includes basic properties common for all pagetypes and the EPiServer PropertyDataCollection and looks like this.

   1: public class PropertiesBase
   2: {
   3:     public PropertyString PageName { get; set; }
   4:     public PropertyString Heading { get; set; }    
   5:     public PropertyDataCollection Properties { get; set; }
   6: }

Accessing the mapped properties

To access the mapped properties we create a generic extensionmethod on the PageData object where we provide a property mapping type.

   1: public static PropertyData GetProperty<T>(this PageData currentPage, Expression<Func<T, PropertyData>> expression) where T : PropertiesBase
   2: {
   3:     var methodExp = (MemberExpression)expression.Body;
   4:     return currentPage.Property.Get(methodExp.Member.Name) ?? currentPage.Property[methodExp.Member.Name];
   5: }

This method takes a lamda expression as argument to allow for some static reflection, wich makes it possible to access the properties in a strongly typed way.

Note that to optimize performance pageData.Property.Get(“myproperty”) is used in the first place to avoid fetching dynamic properties. If we really asked for a dynamic property pageData.Property[“myproperty”] is used as fallback wich do fetch dynamic properties. Read more on this in the SDK under Read-Only PageData Cache.

It will now be possible to access the mapped properties in a strongly typed way  and with assistance of the intellisense on any PageData object like so.

GetPropertyExample1

We could stop right there but to avoid providing the property mapping type each time we need to access a property on CurrentPage, we create new generic base classes based on the standard classes TemplatePage, SimplePage and UserControlBase to take care of that mapping. Example is provided for TemplatePage, the other base classes should look the same.

   1: public class TemplatePage<T> : TemplatePage where T : PropertiesBase
   2: {
   3:     public PropertyData GetProperty(Expression<Func<T, PropertyData>> expression)
   4:     {
   5:         return CurrentPage.GetProperty(expression);
   6:     }
   7: }

Then in our template page we use TemplatePage<T> as our base class like this.

   1: public partial class MyPage : TemplatePage<MyPageProperties>
   2: {
   3:     protected void Page_Load(object sender, EventArgs e)
   4:     {
   5:         var mainBody = GetProperty(x => x.MainBody).ToString();
   6:     }
   7: }

A property mapping type is now provided and GetProperty() on CurrentPage can thus be used without providing the property mapping type each time we need to access a property.

Now, with quite a small effort, we have strongly typed property access thats way more safe and refactorfriendly then using “magic strings”. 

Have your pagetypes built based on your property mappings

By now some of you might think that would it not be nice if all I had to do was to deal with the property mapping classes and have the pagetypes built automatically based on them. That would also assure that the mapped properties actually exist in EPiServer.

This is exactly what my colleague Mikael Nordberg covers in Strongly typed property access- Part two

28 April 2009

Tags:


    Comments

    1. Brilliant! Lambda expression to the rescue :) Looking forward to part 2 and hopefully a killer deployment feature... Nice meeting you in Sundsvall. Say hello to everyone.
    2. Personally, I think the code style looks strange, but it might be just me. How does this relate to the post by Fredrik? http://labs.episerver.com/en/Blogs/Fredrik-Tjarnberg/Dates/2009/3/PageType-Inheritance/
    3. Steve, some of the major differences as I see it is that since this is XML less it allows for avoiding things such as defining property types and PageType inheritance in XML. Another thing is that the core of accessing properties is set on the PageData object, and not on the PageType itself and will thus always be accessable. No matter if we are working with CurrentPage, a childpage or creating a new page. And it needs no tool, just plain C# code.
    4. Daniel, Nice work indeed! Amazing what a small amount of clever code can give you! Steve, It is similar but different :) In vNext of the PageTypeTool (as I call my thingy) the EPiServer properties ends up as CLR properties on "strongly typed" PageData objects. Since it relies on some changes that will be available with R2 SP2 I will blog about it closer to the release.
    5. Fredrik, looking forward to your article.
    6. Great post, Daniel! We use a small executable which runs as a pre-build event in our EPiServer projects. It creates a .cs file which creates classes and properties for all page types by querying the database. It also extracts descriptions etc and inserts them as XML comments. This enables us to trap any property errors at compile-time and also gives us full IntelliSense. Maybe that's close to what Mikael will talk about?
    7. Ted, nice idea with the comments and everything.
    8. Ted, to quote Fredrik, "it is similar but different" :) Basically our solution works the other way around with the property mapping classes as master and the EPiServer database as slave. But all that will be revealed in Mikaels article, so "stay tuned" :)
    9. Hi. If you access the property with pageData.Property.Get("myproperty") you want get inherit values from either fetch data from or from master language.
    10. Anders Hattestad, we're using pageData.Property.Get("myproperty") because according to the SDK this is the fastes way to access a property. The GetProperty will fallback to pageData.Property["myproperty"] to fetch dynamic properties.
    11. Know its faster :), but there is alot going on in the Property["mypropery"] like fallback to master language, and possible override from other components/dll's, but as long as that aint a issue your code is fastest. I like the consept you have made.
    12. Seems to be a solution for everyone here :-) Ted, I want your pre-build script, that sounds really useful.
    13. RFeH1b gezlpidkycig, [url=http://rddeyuhdtavx.com/]rddeyuhdtavx[/url], [link=http://zqudtpbbqvop.com/]zqudtpbbqvop[/link], http://xaxjdrllraij.com/
    Post a comment    
    User verification Image for user verification  
    Daniel Rodin

    About me

    Works for IT service company Steria in Sundsvall, Sweden. Professional focus and interests are architecture and development of web client solutions.

    Syndications


    Archive


    Tag cloud

    EPiTrace logger