PageData extension methods

by Greg 6. October 2010 16:51

Over the last two years of using EPiServer a pattern has emerged when working with a PageData object in a CodeBehind file. I've found that often, it's not enough to simply use the <EPiServer:Property /> control to display a property, sometimes you want to show or hi de an entire region (like an <asp:Panel /> or <asp:PlaceHolder /> ) based on weather a property has a value or not. For example, you might have a basic content template which you need to work both with and without a header image.

Layout with image
Layout with header

Layout without image
Layout without image

When accessing a property of a page that is optional, you can't just dive in and access the value of the property as the property data might be null, so accessing the Value property of it will throw a NullReferenceException. So the usual pattern is to check the property is not null, check the value of the property is not null and then use the value:

if (CurrentPage.Property["Foo"] != null &&
    CurrentPage.Property["Foo"].Value != null)
{
     // Do something
}

This can lead to loads of repetitive and messy code in your CodeBehind so I came up with the following extension method to help ease the constant pain of obtaining a property value:

/// <summary>
/// Gets the value of a property.
/// </summary>
/// <typeparam name="T">The type to cast the value to.</typeparam>
/// <param name="propertyName">The name of the property to fetch.</param>
/// <returns>Returns the value of the property or default(T).</returns>
public static T GetPropertyValue<T>(this PageData pageData, string propertyName)
{
    if (pageData.Property[propertyName] != null &&
        pageData.Property[propertyName].Value != null)
    {
        return (T)pageData.Property[propertyName].Value;
    }
    else
    {
       return default(T);
    }
}

Which you can then use like this:

string foo = CurrentPage.GetPropertyValue<string>("Foo");

If you imagine, in some complex templates you can repeat this conditional pattern five or ten times, this one method can clean your code up a bunch and make it much more readable!

The trouble with databinding

We've been using that extension method in the office for around six months now; I don't think I've accessed a property directly since, but the other day I was doing some databinding and I realised I don't like the way we usually access Properties when binding against a collection of PageData using an <asp:Repeater />.

As I see it, you have two options. Firstly, you can bang a load of server controls in the ItemTemplate and then Find them in the ItemDataBound event, cast the DataItem of the RepeaterItemEventArgs to PageData and bind all your controls there, or you can cast the Container.DataItem to PageData in the front end and get to the properties that way. This means we don't have to go through the lengthy process of finding controls but it does mean casting the Container.DataItem every time. So how can we combine the Extension method from before with the simplicity of binding in the aspx rather than the codebehind?

Extending the object

Within the <ItemTemplate>, Container.DataItem is of type object, so the only way we can add custom code to that is by creating an extension method for object itself, and as such, extending every object in our application. 

public static T GetPropertyValue<T>(this object pageData, string propertyName)
{
    // try to cast the current object to PageData to access it's properties 
    PageData data = pageData as PageData;
    if(null == data) return default(T);
    if (data.Property[propertyName] != null &&
        data.Property[propertyName].Value != null)
    {
        return (T)data.Property[propertyName].Value;
    }
    else
    {
        return default(T);
    }
}

Not a good idea, I hear you say; and I agree! For a start it pollutes the entire application with a method that you only want on objects of one type. Secondly, other developers might try to use it on non-PageData objects thinking it works somehow works for them and last, I didn't like the duplication of the logic, but that's easily fixed, right. It's just a terrible idea and I wasn't happy with the prospect but I allowed myself to continue messing around to see where I got.

My next thought was, what if we move the object version of the extension method into a separate namespace away from core namespace of the application and away from all the other objects. We can then just import the namespace in the aspx, either through an <%@ Import %> tag or in the <namespaces> tag in the web.config. I did that and I also removed the duplicated code, like so:

namespace Application.Extensions.UI
{
    public static class PageDataExtensionsUI
    {
        public static T GetPropertyValue<T>(this object pageData, string propertyName)
        {
            PageData data = pageData as PageData;
            if(null == data) return default(T);

            return data.GetPropertyValue<T>(propertyName);
        }
    }
}

You can then call it on the Container.DataItem when DataBinding:

<asp:Repeater runat="server">
    <ItemTemplate>
       <p><%# Container.DataItem.GetPropertyValue("Foo") %></p>
    </ItemTemplate>
</asp:Repeater>

This blew right up in my face wiith a big fat StackOverflowException which, it turns out, is down to how the C# compiler resolves extension methods, favouring those in more local namespaces to those further afield. 

This is an easy fix though, because extension methods are just static methods with a little weird syntax, so I changed the way the PageData version of the method is called and it all works great.

namespace Application.Extensions.UI
{
    public static class PageDataExtensionsUI
    {
        public static T GetPropertyValue<T>(this object pageData, string propertyName)
        {
            PageData data = pageData as PageData;
            if(null == data) return default(T);

            return PageDataExtensions.GetPropertyValue<T>(data, propertyName);
        }
    }
}

In Conclusion

I haven't done much data binding since writing this code to know how it works in practice and it hasn't spread beyond the project I implemented it to have any of the other team members run into it.

I'm still not entirely convinced it's the right way to go but only time will tell.

Tags: ,

EPiServer

EPiServer Certified Developer #712

by Greg 5. October 2010 08:40

Back in July I popped down to London with a colleague, Stephen, to take the EPiServer CMS certification test which we both passed qualifying twentysix as a Premium Solutions Partner.

EPiServer certified developer logoToday, our certificates arrived and I'm proud to say I am EPiServer Certified Developer #712 and Stephen is ECD #713:

My ECD Certificate

I've been using EPiServer for nearly two years now, having taken the basic developer training at the end of January 2009 and in that time I've worked on some large and exciting sites but the prospect of the certification, the possiblity of failing it and the peer pressure that comes with was quite daunting. In the two years I've created two or three sites which I would call a Standard build, comprising a single web and/or database server, no mirroring, no custom page providers no use of add-ons or 3rd party integrations. 

I've also created a few sites which weren't standard, integrating with bespoke and off-the-shelf 3rd party systems. Mirrored and load-balanced deployments. Deployments which use SQL Server clusters and most recently, I've written a Page Provider to integrate nopCommerce into a CMS 6 site.

On top of all this I've done the usual amount of hacking around in the SDK, re-written and extended a few of the EPiServer controls to add additional functionality (Such as Alternating Item Templates in the PageList and NewsList control [post to follow]).

Tips for passing the exam

It was quite hard to find a good exam guide for the certification and we found a lot of blog posts saying how hard the test was which I don't entirely agree with. It wasn't a walk in the park but it was fairly straight forward.

Read the Developers Guide

I can't link you straight to it because of the funky JavaScript navigation (you can find it easily from the SDK documentation).The developer guide is a gold mine!

If there are areas EPiServer you haven't worked with before but you have a decent understanding of the core functionality, you can pick up a lot from these documents. A few of the questions I knew instantly as I'd re-read and revised all the articles in this section, some of these questions were on functionality I'd never used.

Read the Tech Notes

Same goes for the Tech Notes as does the Developer Guide, read them all. The're not as long or detailed as the articles in the Dev Guide but they helped me answer a few questions.

Re-read the editor and administrator manuals

When someone is asking how to achieve something in the CMS from a user point of view, I sometimes find I'm not the best person to ask, while I do Develop EPiServer sites I don't spend hours in the Editor working with trees of pages, workflows and all the other gubbinz that make up the CMS. To this end, I'm glad I gave the Editor Manual and the Administrator Manual another read.

Read the internet

I'm not suggesting you read all of the internet, but if you're reading this, the chances are you've already Googled for tips on passing the exam. Here are some that we found:

 

 

Good luck!

Tags: ,

EPiServer

Programming in Haskell - Chapter 3

by Greg 3. October 2010 20:07

This has been sat on my pad for about a week now.

My marks for Chapter 3 of Programming in Haskell.

Exercise 1 - What are the type of the following values?

Part 1:

[ 'a', 'b', 'c' ]
-- has type 
[ Char ]

Correct

Part 2:

( 'a', 'b', 'c' )
-- has type 
( Char , Char , Char )

Correct

Part 3:

[ ( False , 'O' ) , ( True , '1' ) ]
-- has type 
[ ( Bool , Char ) ]

Correct

Part 4:

( [ False , True ] , [ '0' , '1' ] )
-- has type 
( [ Bool ], [ Char ] )

Correct

Part 5:

Here is what I thought:

[ tail , init , reverse ]
-- has type   
[ &fnof; ]

I was wrong. I was unsure how to denote the type of a function within the context of the type of another function, but seeing the output from Hugs helped me realise how this is done. You denote a functions type by writing out its type, if you follow.

The correct answer: 

[ tail , init , reverse ]
-- has type   
[ [ a ] -> [ a ] ]

Incorrect

I've learned, or rather realised something from getting part 5 wrong, the way to express the type of a function. This really was a moment of realisation, as I've correctly written the type [o \rrrrrrrrrrrrrrrrrrrrrrrrrrrttttttf cat on the keyboard] of a function in my working for Problem 1 of Project Euler. It was so obvious, I couldn't see the wood for the trees.

Exercise 2 - What are the types of the following functions?

Part 1:

second xs    = head (tail xs)
-- has type 
second       :: [ a ] -> a

Correct

Part 2:

swap ( x , y ) = ( y , x )
-- has type 
swap           :: ( a , b ) -> ( a , b )

Correct (ish)

I was right in theory but I used x and y to denote the types for the arguments however; it is Haskell convention that type variables are usually a, b, c... I made this same mistake in the rest answers but as I was correct in the theory, if not the notation, I've given myself the mark.

Part 3:

pair      = ( x , y )
-- has type 
pair      :: a -> b -> ( a , b )

Again, I originally used x and y for the type variables.

Correct

Part 4:

double x    = x * 2
-- has type 
double      :: Num a => a -> a

Correct

Part 5:

palindrome xs   = reverse xs == xs
-- has type 
palindrome      :: Eq a => [ a ] -> Bool

Correct

Part 6:

twice ƒ x    = ƒ ( ƒ x )
-- has type 
twice        :: ƒ -> x

(Completely) Incorrect

I got that last one wrong! As mentioned before, not realising how to write the type of a function within the type of another function, I was looking for some way to express "argument blah is a function". Having made the realisation stated earlier, the correct answer makes complete sense.

Exercise 3 requires no formal answers but in working through my answers using Hugs I gained the understanding of how to express a function.

Exercise 4 - Why is it not feasible in general for function types to be instances of the Eq class? When is it feasible? Hint: two functions of the same type are equal if they always return equal results for equal arguments.

Answer: It is not feasible for the majority of functions to be instances of the Eq class, and therefore return the same result given the same arguments because you would rarely (if ever) implement two functions which took the same arguments and did the same thing. It might be feasible if you were writing two different implementations of a software for fail safe reasons. Maybe.

I'm not going to lie, I'm about to learn something in a moment when I flick to the PDF of answers and find out what the correct answer is.

And the winner is... 

Incorrect

The correct answer is that it's too complicated and time consuming to check all possible combinations of inputs and output of a function when it has a lot of possible inputs and outputs. It is feasible to check the equality of a function when it has few inputs and few outputs.

This was my first thought (and it's a really obvious one) but I have a tendency to over think things and get too deep into the problem. 

Marks for Chapter 3 : 9 out of a possible 12 but some important lessons learned. 

Tags: ,

Haskell

Project Euler - Problem 1 in Haskell

by Greg 2. October 2010 21:04

I originally did this problem about a year ago using C# so I already had the answer but in my quest to learn Haskell I've chosen to re-do it. 

I have a couple of notes I'd like to document, partly for my own benefit and partly to state my purpose. Firstly I've left the actual answer out so as not to give the entire game away. Secondly, I'm not sure on my Haskell style as yet, as this is the first program I've written. I've only read two and a half chapters or Programming in Haskell so I'm not fully l33t at it yet so I think I'm gonna reserve the right to come back in the future and amend the code below. I guess we'll see as I post some more answers and get more familiar with Haskell, and lastly, the first time I run this code in WinHugs I get the time stated below, the second and subsequent runs reports 0.0000000000000000 seconds. I've used the time greater than zero just to have a time as I'm not sure if this stuff is cached or not. As and when I learn the correct method to benchmark a Haskell script I'll update this with a more accurate time.

While I'm on about benchmarking, I'm currently working on a Dell Precision M4400 running a Core 2 Duo P8600 (2.4GHz) with 4GB ram, a 500GB 7200rpm Seagate Momentous disk all running Windows 7 Pro 64Bit. It get's a 5.9 on the Windows Experience Index with the lowest score coming from the.

 

This will be the same hardware for all the timings unless I get something new from but I doubt that for a while.

So without further ado. here is my solution for Problem 1.

-- Project Euler - Problem 1
-- http://projecteuler.net/index.php?section=problems&id=1
-- If we list all the natural numbers below 10 that are 
-- multiples of 3 or 5 we get 3, 5, 6 and 9. 
-- The sum of these multiples is 23.
--
-- Find the sum of all the multiples of 3 or 5 below 1000.
--
-- 08/09/2010
--
-- Time taken: 0.0312002000000000 sec

import Text.Printf
import Control.Exception
import System.CPUTime


-- program

isMultiple		::	Int -> Int -> Bool
isMultiple n x	= 	(x `mod` n) == 0

is5				::	Int -> Bool
is5 x 			=	isMultiple 5 x

is3				::	Int -> Bool
is3 x			=	isMultiple 3 x


problem1		::	[Int] -> Int
problem1 []		= 	0
problem1 (x:xs)		=	if is3 x || is5 x
					then
						x + problem1 xs
					else
						0 + problem1 xs



-- utils

time 			::	IO t -> IO t
time a 			=	do
    start <- getCPUTime
    v <- a
    end   <- getCPUTime
    let diff = (fromIntegral (end - start)) / (10^12)
    printf "Computation time: %0.16f sec\n" (diff :: Double)
    return v
 
main 			=	do
    putStrLn "Starting..."
    time $ problem1 [1..999] `seq` return ()
    printf "Result: %d\n" (problem1 [1..999])
    putStrLn "Done."

 

 

 

 

Tags: ,

Haskell