<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Greg Brant</title><link href="http://world.optimizely.com" /><updated>2011-09-11T12:00:00.0000000Z</updated><id>https://world.optimizely.com/blogs/Greg-Brant/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>EPiServer and MvcMiniProfiler - Profiled Base Classes</title><link href="http://blog.gregbrant.com/post.aspx?id=16718de0-f3d8-4370-8bfe-90fbd28bb414" /><id>&lt;p&gt;So far we&#39;ve had &lt;a href=&quot;http://blog.gregbrant.com/post/EPiServer-and-MvcMiniProfiler-A-first-look.aspx&quot;&gt;a basic introduction to MvcMiniProfiler and how to get it working with EPiServer&lt;/a&gt;, we&#39;ve also looked at &lt;a href=&quot;http://blog.gregbrant.com/post/EPiServer-and-MvcMiniProfiler-A-Profiled-DataFactory.aspx&quot;&gt;a version of DataFactory that gives profiling data about its calls&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This time I&#39;m going to look at giving easier access to stepping the profiler, not that it&#39;s exactly hard to begin with, as well as building some basic profiling into some base classes so that there is always a minimum of profiling in your pages.&lt;/p&gt;
&lt;p&gt;This is all work in progress or &lt;em&gt;thinking in code&lt;/em&gt; if you will. It hasn&#39;t been road tested much and I&#39;m not sure it&#39;s the right recipe, so please feel free to leave feedback in the comments.&lt;/p&gt;
&lt;h2&gt;Stepping The Profiler&lt;/h2&gt;
&lt;p&gt;Stepping the profiler is usually achieved with a call to MvcMiniProfiler.MiniProfiler.StepStatic or MvcMiniProfiler.MiniProfiler.Current.Step. This might get a bit bloated so let&#39;s see if we can shorten it some. As I see it, there are three places we&#39;re going to want to step the profiler from:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Page Templates&lt;/li&gt;
&lt;li&gt;Master Pages&lt;/li&gt;
&lt;li&gt;User Controls&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So what about hanging a &lt;em&gt;Step&lt;/em&gt; method off each of these types:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
using System.Web.UI;
using MvcMiniProfiler;

namespace EPiServer.MiniProfiler
{
    public static class ProfilerExtensions
    {
        public static IDisposable StepProfilerEx(this PageBase page, string name, ProfileLevel level = ProfileLevel.Info)
        {
            string typeName = page.GetType().Name;
            return MvcMiniProfiler.MiniProfiler.StepStatic(string.Format(&quot;{0} {1}&quot;, typeName, name), level);
        }

        public static IDisposable StepProfilerEx(this MasterPage page, string name, ProfileLevel level = ProfileLevel.Info)
        {
            string typeName = page.GetType().Name;
            return MvcMiniProfiler.MiniProfiler.StepStatic(string.Format(&quot;{0} {1}&quot;, typeName, name), level);
        }

        public static IDisposable StepProfilerEx(this UserControl control, string name, ProfileLevel level = ProfileLevel.Info)
        {
            string typeName = control.GetType().Name;
            return MvcMiniProfiler.MiniProfiler.StepStatic(string.Format(&quot;{0} {1}&quot;, typeName, name), level);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;Here I&#39;ve added three Extension Methods to a class which combines the type name of the caller along with the user-defined step name. This gives us a clue as to where the code is being executed, the resultant profile looks something like this:&lt;/p&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;&lt;img style=&quot;border-style: initial; border-color: initial; display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f9%2fStepProfilerEx.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2 class=&quot;brush: c-sharp;&quot;&gt;Profiled Base Classes&amp;nbsp;&lt;/h2&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;My next idea is to provide profiled versions of the page events such as OnLoad and OnPreRender as well as profiled versions of the EPiServer API methods like PageBase.GetPage. The full code can be &lt;a href=&quot;http://blog.gregbrant.com/file.axd?file=2011%2f9%2fProfilerExtensions.zip&quot;&gt;downloaded in this zip file&lt;/a&gt;, but for illustrative purposes part of my ProfiledTemplatePage might look like this:&lt;/p&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
using System.Web.UI.WebControls;
using EPiServer.Core;
using MvcMiniProfiler;

namespace EPiServer.MiniProfiler
{
    public abstract class ProfiledTemplatePage : TemplatePage
    {
        private string typeName;

        public MvcMiniProfiler.MiniProfiler Profiler
        {
            get { return MvcMiniProfiler.MiniProfiler.Current; }
        }

        public ProfiledTemplatePage()
        {
            // Store the name of the current type for profiling steps.
            typeName = this.GetType().Name;
        }

        public IDisposable StepProfiler(string name, ProfileLevel level = ProfileLevel.Info)
        {
            return Profiler.Step(string.Format(&quot;{0} {1}&quot;, typeName, name), level);
        }

        #region Profiled events

        protected virtual void OnLoadProfiled(EventArgs e) { }

        protected virtual void OnLoadCompleteProfiled(EventArgs e) { }

        protected internal virtual void OnPreRenderProfiled(EventArgs e) { }

        // Other profiled events here...

        #endregion

        #region PageBase overrides

        public override PageData GetPage(PageReference pageLink)
        {
            using (StepProfiler(&quot;GetPage&quot;))
                return base.GetPage(pageLink);
        }

        // Other profiled EPiServer methods here...

        #endregion

        #region Control overrides

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            using (StepProfiler(&quot;OnLoadProfiled&quot;))
                OnLoadProfiled(e);
        }

        protected override void OnLoadComplete(EventArgs e)
        {
            base.OnLoadComplete(e);
            using (StepProfiler(&quot;OnLoadCompleteProfiled&quot;))
                OnLoadCompleteProfiled(e);
        }

        // Wrap other events here...

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            using (StepProfiler(&quot;OnPreRenderProfiled&quot;))
                OnPreRenderProfiled(e);

            // Logic to add Profiler Includes to the &amp;lt;head&amp;gt; of the page. 
            string html = MvcMiniProfiler.MiniProfiler.RenderIncludes().ToHtmlString();
            Page.Header.Controls.Add(new Literal
            {
                Mode = LiteralMode.PassThrough,
                Text = html
            });
        }

        #endregion
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a pretty big code snippet as it stands so I&#39;ve left out many of the events and methods, it&#39;s worth noting that OnPreRender wraps the OnPreRenderProfiled method but then adds the profiler includes to the &amp;lt;head&amp;gt; of the page. There are similar classes in the form of ProfiledUserControl and ProfiledMasterPage, ProfiledTemplatePage is the only one to render the includes to the head.&lt;/p&gt;
&lt;p&gt;Using the code is pretty obvious, you inherit from the base class and override the Profiled versions of events:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using EPiServer.Core;
using EPiServer.MiniProfiler;

namespace EPiServer_MiniProfiler.Templates
{
    public partial class News : ProfiledTemplatePage
    {
        protected override void OnLoadProfiled(EventArgs e)
        {
            NewsItems.DataSource = GetChildren(CurrentPageLink);
            using (StepProfiler(&quot;Binding news list&quot;))
                NewsItems.DataBind();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Work In Progress&lt;/h2&gt;
&lt;p&gt;I&#39;m not 100% about this implementation as it&#39;s not a like-for-like replacement for TemplatePage. It might be easy for a developer who is new to the project to simply use OnLoad rather than OnLoadProfiled. The other thing is that Auto-Wireup events such as Page_Load are triggered within the built-in OnLoad events. This raises the idea of implementing a Page_LoadProfiled but I&#39;m not sure this isn&#39;t just throwing &lt;em&gt;good&lt;/em&gt; code after bad.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;protected virtual void OnLoadProfiled(EventArgs e)
{
    CallEvent(&quot;Page_LoadProfiled&quot;, e);
}

private void CallEvent(string eventName, EventArgs e)
{
    var t = this.GetType();
    var method = t.GetMethod(eventName);
    if (method != null)
        method.Invoke(this, new[] { e });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As I&#39;ve said, these are some first thoughts on building profiling data into your EPiServer working practices and I haven&#39;t tried them out enough to be sure of their worth.&lt;/p&gt;
&lt;h2&gt;Next Time&lt;/h2&gt;
&lt;p&gt;Next time we&#39;ll look at locking down the trace information so that it&#39;s only visible to the people you want to see it.&lt;/p&gt;</id><updated>2011-09-11T12:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>EPiServer and MvcMiniProfiler - A Profiled DataFactory</title><link href="http://blog.gregbrant.com/post.aspx?id=5d4638ce-98ce-43b3-99b3-660030e46b59" /><id>&lt;p&gt;&lt;a href=&quot;http://blog.gregbrant.com/post/EPiServer-and-MvcMiniProfiler-A-first-look.aspx&quot;&gt;Last time we took a quick look into MvcMiniProfiler&lt;/a&gt;, how to get it up and running on EPiServer and the basics of profiling code.&lt;/p&gt;
&lt;p&gt;This time, we&#39;ll take a look at the DataFactory and profiling it&#39;s use.&lt;/p&gt;
&lt;h2&gt;ProfiledDataFactory&lt;/h2&gt;
&lt;p&gt;A lot of the time, when you&#39;re not working with the CurrentPage PageData object, you&#39;re working with the EPiServer DataFactory to obtain and manipulate PageData objects. ProfiledDataFactory is a simple wrapper around the default DataFactory; I&#39;ve implemented all the methods which aren&#39;t marked with the Obsolete attribute so the class is a drop-in replacement for EPiServer.DataFactory. As a side note, if EPiServer employed Dependency Injection or was more losely coupled, we might have been able to replace the default DataFactory throughout the framework. (double click the code to select it as plain text)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System.Collections.Generic;
using EPiServer.Configuration;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAccess;
using EPiServer.Security;
using MvcProf = MvcMiniProfiler;

namespace EPiServer.MiniProfiler
{
    public sealed class ProfiledDataFactory
    {
        private static ProfiledDataFactory _instance = new ProfiledDataFactory();

        public static ProfiledDataFactory Instance
        {
            get { return _instance; }
        }

        public PageReference Copy(PageReference pageLink, PageReference destinationLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Copy&quot;))
                return DataFactory.Instance.Copy(pageLink, destinationLink);
        }

        public PageReference Copy(PageReference pageLink, PageReference destinationLink, bool allowThreading)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Copy&quot;))
                return DataFactory.Instance.Copy(pageLink, destinationLink, allowThreading);
        }

        public PageReference Copy(PageReference pageLink, PageReference destinationLink, bool publishOnDestination, bool allowThreading)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Copy&quot;))
                return DataFactory.Instance.Copy(pageLink, destinationLink, publishOnDestination, allowThreading);
        }

        public PageReference Copy(PageReference pageLink, PageReference destinationLink, AccessLevel requiredSourceAccess, AccessLevel requiredDestinationAccess, bool publishOnDestination, bool allowThreading)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Copy&quot;))
                return DataFactory.Instance.Copy(pageLink, destinationLink, requiredSourceAccess, requiredDestinationAccess, publishOnDestination, allowThreading);
        }

        public PageData CreateLanguageBranch(PageReference pageLink, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory CreateLanguageBranch&quot;))
                return DataFactory.Instance.CreateLanguageBranch(pageLink, selector);
        }

        public PageData CreateLanguageBranch(PageReference pageLink, ILanguageSelector selector, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory CreateLanguageBranch&quot;))
                return DataFactory.Instance.CreateLanguageBranch(pageLink, selector, access);
        }

        public void Delete(PageReference pageLink, bool forceDelete)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Delete&quot;))
                DataFactory.Instance.Delete(pageLink, forceDelete);
        }

        public void Delete(PageReference pageLink, bool forceDelete, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Delete&quot;))
                DataFactory.Instance.Delete(pageLink, forceDelete, access);
        }

        public void DeleteChildren(PageReference pageLink, bool forceDelete)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteChildren&quot;))
                DataFactory.Instance.DeleteChildren(pageLink, forceDelete);
        }

        public void DeleteChildren(PageReference pageLink, bool forceDelete, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteChildren&quot;))
                DataFactory.Instance.DeleteChildren(pageLink, forceDelete, access);
        }

        public void DeleteLanguageBranch(PageReference pageLink, string languageBranch)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteLanguageBranch&quot;))
                DataFactory.Instance.DeleteLanguageBranch(pageLink, languageBranch);
        }

        public void DeleteLanguageBranch(PageReference pageLink, string languageBranch, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteLanguageBranch&quot;))
                DataFactory.Instance.DeleteLanguageBranch(pageLink, languageBranch, access);
        }

        public void DeleteVersion(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteVersion&quot;))
                DataFactory.Instance.DeleteVersion(pageLink);
        }

        public void DeleteVersion(PageReference pageLink, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory DeleteVersion&quot;))
                DataFactory.Instance.DeleteVersion(pageLink, access);
        }

        public PageDataCollection FindAllPagesWithCriteria(PageReference pageLink, PropertyCriteriaCollection criterias, string languageBranch, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory FindAllPagesWithCriteria&quot;))
                return DataFactory.Instance.FindAllPagesWithCriteria(pageLink, criterias, languageBranch, selector);
        }

        public PageDataCollection FindPagesWithCriteria(PageReference pageLink, PropertyCriteriaCollection criterias)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory FindPagesWithCriteria&quot;))
                return DataFactory.Instance.FindPagesWithCriteria(pageLink, criterias);
        }

        public PageDataCollection FindPagesWithCriteria(PageReference pageLink, PropertyCriteriaCollection criterias, string languageBranch)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory FindPagesWithCriteria&quot;))
                return DataFactory.Instance.FindPagesWithCriteria(pageLink, criterias, languageBranch);
        }

        public PageDataCollection FindPagesWithCriteria(PageReference pageLink, PropertyCriteriaCollection criterias, string languageBranch, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory FindPagesWithCriteria&quot;))
                return DataFactory.Instance.FindPagesWithCriteria(pageLink, criterias, languageBranch, selector);
        }

        public PageDataCollection GetChildren(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetChildren&quot;))
                return DataFactory.Instance.GetChildren(pageLink);
        }

        public PageDataCollection GetChildren(PageReference pageLink, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetChildren&quot;))
                return DataFactory.Instance.GetChildren(pageLink, selector);
        }

        public PageDataCollection GetChildren(PageReference pageLink, ILanguageSelector selector, int startIndex, int maxRows)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetChildren&quot;))
                return DataFactory.Instance.GetChildren(pageLink, selector, startIndex, maxRows);
        }

        public PageData GetDefaultPageData(PageReference parentPageLink, int pageTypeID)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetDefaultPageData&quot;))
                return DataFactory.Instance.GetDefaultPageData(parentPageLink, pageTypeID);
        }

        public PageData GetDefaultPageData(PageReference parentPageLink, string pageTypeName)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetDefaultPageData&quot;))
                return DataFactory.Instance.GetDefaultPageData(parentPageLink, pageTypeName);
        }

        public PageData GetDefaultPageData(PageReference parentPageLink, int pageTypeID, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetDefaultPageData&quot;))
                return DataFactory.Instance.GetDefaultPageData(parentPageLink, pageTypeID, selector);
        }

        public PageData GetDefaultPageData(PageReference parentPageLink, string pageTypeName, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetDefaultPageData&quot;))
                return DataFactory.Instance.GetDefaultPageData(parentPageLink, pageTypeName, selector);
        }

        public IList&amp;lt;PageReference&amp;gt; GetDescendents(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetDescendents&quot;))
                return DataFactory.Instance.GetDescendents(pageLink);
        }

        public PageDataCollection GetLanguageBranches(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetLanguageBranches&quot;))
                return DataFactory.Instance.GetLanguageBranches(pageLink);
        }

        public PageReferenceCollection GetLinksToPages(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetLinksToPages&quot;))
                return DataFactory.Instance.GetLinksToPages(pageLink);
        }

        public PageData GetPage(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetPage&quot;))
                return DataFactory.Instance.GetPage(pageLink);
        }

        public PageData GetPage(PageReference pageLink, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetPage&quot;))
                return DataFactory.Instance.GetPage(pageLink, selector);
        }

        public PageProviderBase GetPageProvider(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetPageProvider&quot;))
                return DataFactory.Instance.GetPageProvider(pageLink);
        }

        public PageProviderBase GetPageProvider(string remoteSiteName)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetPageProvider&quot;))
                return DataFactory.Instance.GetPageProvider(remoteSiteName);
        }

        public PageDataCollection GetPages(IList&amp;lt;PageReference&amp;gt; pageLinks, ILanguageSelector selector)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetPages&quot;))
                return DataFactory.Instance.GetPages(pageLinks, selector);
        }

        public PagePath GetParents(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetParents&quot;))
                return DataFactory.Instance.GetParents(pageLink);
        }

        public Settings GetSettingsFromPage(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetSettingsFromPage&quot;))
                return DataFactory.Instance.GetSettingsFromPage(pageLink);
        }

        public Settings GetSettingsFromPage(PageReference pageLink, bool fallbackToStartPageId)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory GetSettingsFromPage&quot;))
                return DataFactory.Instance.GetSettingsFromPage(pageLink, fallbackToStartPageId);
        }

        public bool IsCapabilitySupported(PageReference pageLink, PageProviderCapabilities capability)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory IsCapabilitySupported&quot;))
                return DataFactory.Instance.IsCapabilitySupported(pageLink, capability);
        }

        public bool IsWastebasket(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory IsWastebasket&quot;))
                return DataFactory.Instance.IsWastebasket(pageLink);
        }

        public PageDataCollection ListDelayedPublish()
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ListDelayedPublish&quot;))
                return DataFactory.Instance.ListDelayedPublish();
        }

        public PageVersionCollection ListPublishedVersions(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ListPublishedVersions&quot;))
                return DataFactory.Instance.ListPublishedVersions(pageLink);
        }

        public PageVersionCollection ListVersions(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ListVersions&quot;))
                return DataFactory.Instance.ListVersions(pageLink);
        }

        public PageVersionCollection ListVersions(PageReference pageLink, string languageBranch)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ListVersions&quot;))
                return DataFactory.Instance.ListVersions(pageLink, languageBranch);
        }

        public PageVersion LoadPublishedVersion(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory LoadPublishedVersion&quot;))
                return DataFactory.Instance.LoadPublishedVersion(pageLink);
        }

        public PageVersion LoadPublishedVersion(PageReference pageLink, string languageBranch)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory LoadPublishedVersion&quot;))
                return DataFactory.Instance.LoadPublishedVersion(pageLink, languageBranch);
        }

        public PageVersion LoadVersion(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory LoadVersion&quot;))
                return DataFactory.Instance.LoadVersion(pageLink);
        }

        public void Move(PageReference pageLink, PageReference destinationLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Move&quot;))
                DataFactory.Instance.Move(pageLink, destinationLink);
        }

        public void Move(PageReference pageLink, PageReference destinationLink, AccessLevel requiredSourceAccess, AccessLevel requiredDestinationAccess)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Move&quot;))
                DataFactory.Instance.Move(pageLink, destinationLink, requiredSourceAccess, requiredDestinationAccess);
        }

        public void MoveToWastebasket(PageReference pageLink)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory MoveToWastebasket&quot;))
                DataFactory.Instance.MoveToWastebasket(pageLink);
        }

        public void ResetCounters()
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ResetCounters&quot;))
                DataFactory.Instance.ResetCounters();
        }

        public PageReference ResolvePageFolder(int pageFolderId)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory ResolvePageFolder&quot;))
                return DataFactory.Instance.ResolvePageFolder(pageFolderId);
        }

        public PageReference Save(PageData page, SaveAction action)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Save&quot;))
                return DataFactory.Instance.Save(page, action);
        }

        public PageReference Save(PageData page, SaveAction action, AccessLevel access)
        {
            using (MvcProf.MiniProfiler.StepStatic(&quot;ProfiledDataFactory Save&quot;))
                return DataFactory.Instance.Save(page, action, access);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;All we need to do now is replace and calls to &lt;em&gt;DataFactory.Instance&lt;/em&gt; with &lt;em&gt;ProfiledDataFactory.Instance&lt;/em&gt;.&lt;/p&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    NewsItems.DataSource = &lt;strong&gt;ProfiledDataFactory&lt;/strong&gt;.Instance.GetChildren(CurrentPageLink);
    NewsItems.DataBind();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;brush: c-sharp;&quot;&gt;This will give us profile information like so:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fProfiledDataFactoryGetChildren.PNG&quot; alt=&quot;Profile data showing call to ProfiledDataFactory.Instance.GetChildren&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Caveat&lt;/h2&gt;
&lt;p&gt;A lot of the DataFactory methods such as GetPage are duplicated within the PageBase class. These methods simply wrap calls to DataFactory.Instance.GetPage and the like. &lt;strong&gt;If you use these methods, they won&#39;t provide any profile information because they&#39;re not using the ProfiledDataFactory&lt;/strong&gt;. As I mentioned earlier, if EPiServer allowed us to replace DataFactory.Instance with anything that implements an IDataFactory interface or an object which inherited from&amp;nbsp;PageStoreBase, we&#39;d be able to plug this ProfiledDataStore in throughout our EPiServer application.&lt;/p&gt;
&lt;h2&gt;Next Time&lt;/h2&gt;
&lt;p&gt;In the next post, we&#39;ll explore replacing some of the EPiServer base classes for pages and user controls to get some&amp;nbsp;basic profiling infrastructure within your application.&lt;/p&gt;</id><updated>2011-08-09T13:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>EPiServer and MvcMiniProfiler - A first look</title><link href="http://blog.gregbrant.com/post.aspx?id=908373e2-a8b3-4d6b-a700-c98a4a3e3b10" /><id>&lt;p&gt;It wasn&#39;t long after I started using EPiServer that I notices&amp;nbsp;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/94c55d08.aspx&quot; target=&quot;_blank&quot;&gt;Page Output for ASP.NET Trace&lt;/a&gt; doesn&#39;t work with the CMS (I even took the time to file a bug with EPiServer but I can&#39;t find it now to link to :( ). After some messing around I discovered the only way to show Trace page output is by ending the response prematurely, for example sticking a Response.End() in the PreRender, but that&#39;s not a good idea, right... The other alternative is to use trace.axd which isn&#39;t a disaster but it&#39;s not entirely convenient.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/p/mvc-mini-profiler/&quot; target=&quot;_blank&quot;&gt;MvcMiniProfiler&lt;/a&gt; is a new tool by the good folks over at &lt;a href=&quot;http://stackexchange.com/&quot; target=&quot;_blank&quot;&gt;Stack Exchange&lt;/a&gt; which gives a really easy and clean API for tracing within your page requests, it works for the main request and any AJAX calls. Many EPiServer projects require some bespoke data access beyond that usual EPiServer Pages and Properties model, to this end, MiniProfiler has a custom SqlConnection which provides profiling info for your queries that can be used with all of your favourite data access technologies.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;m going to walk you through the basics of getting MvcMiniProfiler up and running with EPiServer.&lt;/p&gt;
&lt;h2&gt;NuGet&lt;/h2&gt;
&lt;p&gt;First of all, you&#39;ll need to &lt;a href=&quot;http://nuget.org/&quot; target=&quot;_blank&quot;&gt;install NuGet from NuGet.org&lt;/a&gt; or the Visual Studio Extension Manager. We&#39;ll need this for two things, installing MvcMiniProfiler but before that we&#39;ll need to upgrade our EPiServer project to .NET 4.0.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fNuGetExtensionManager600.png&quot; alt=&quot;Installing NuGet from the Visual Studio Extension Manager&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You could upgrade from .NET 3.5 to 4.0 manually but luckily for you, there&#39;s a package on the &lt;a href=&quot;http://nuget.episerver.com/&quot; target=&quot;_blank&quot;&gt;EPiServer NuGet gallery&lt;/a&gt; that will do it for you in a couple of seconds. Once you&#39;ve got NuGet installed, edit the Package Manager Settings and add the EPiServer feed (http://nuget.episerver.com/feed/packages.svc) as a source.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fEPiServerNuGetPackageSource.png&quot; alt=&quot;Adding the EPiServer Package Source to NuGet&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Next select All in the Package Source menu&amp;nbsp;&lt;/span&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fPackageSourceSelectAll.png&quot; alt=&quot;Select all in the package Manager source menu&quot; /&gt;&lt;span&gt;&amp;nbsp;then type the following at the Package Manager prompt:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;PM&amp;gt; Install-Package EPiServerCMS6ToNetFour&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hit return and a couple of seconds later, your app will be upgraded to .NET 4.&lt;/p&gt;
&lt;p&gt;Now that we&#39;re running on the right platform, we can install MvcMiniProfiler. This package is on the official NuGet feed (but if your Package Source is still set to All you&#39;re golden) so install it with the following:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;PM&amp;gt; Install-Package MiniProfiler&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Basic Setup&lt;/h2&gt;
&lt;p&gt;Now that NuGet has taken care of downloading the required DLLs and added a reference to your project we&#39;re ready to start profiling. Note that the new DLLs are in a &lt;em&gt;packages&lt;/em&gt; folder in the directory above your web application. There is also a packages.config in the root of your application; you might want to add these to source control.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Getting MvcMiniProfiler up and running is really easy, all we need to do is four simple things; first, start the profiler when a request starts, then stop it when a request ends. The Application class (Global.asax) has the perfect events for this. I personally like to add a CodeBehind to my Global.asax, so here&#39;s my code:&lt;/p&gt;
&lt;p&gt;Global.asax&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;%@ Application Language=&quot;C#&quot; Inherits=&quot;EPiServer_MiniProfiler.Global&quot; 
            CodeBehind=&quot;Global.asax.cs&quot; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Global.asax.cs&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
using System.Web;
using MvcMiniProfiler;

namespace EPiServer_MiniProfiler
{
    public class Global : EPiServer.Global
    {
        void Application_BeginRequest(object sender, EventArgs e)
        {
            MiniProfiler.Start();
        }

        void Application_EndRequest(object sender, EventArgs e)
        {
            MiniProfiler.Stop();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thirdly, we need to profile some code. This is done in a really clever way, making use of &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.idisposable.aspx&quot; target=&quot;_blank&quot;&gt;IDisposable&lt;/a&gt; and the &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/yh598w02.aspx&quot; target=&quot;_blank&quot;&gt;using statement&lt;/a&gt;. Create a new EPiServer template and in the OnLoad event, add the following code:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    using (MiniProfiler.StepStatic(&quot;Some long running step&quot;))
    {
        // Do some work here
        Thread.Sleep(123);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Last but not least we need to render the generated JavaScript to the page. This is made super easy, simply add the following to the &amp;lt;head&amp;gt; of your page:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;%= MvcMiniProfiler.MiniProfiler.RenderIncludes().ToHtmlString() %&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Now build your project and visit your template. In the top left hand corner you should see a little tab like this:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fMiniProfilerTab.png&quot; alt=&quot;The MvcMiniProfiler tab&quot; /&gt;&lt;/p&gt;
&lt;p&gt;and clicking the tab will show the non-trivial events that were profiled, like so:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fMiniProfilerNonTrivialEvents.png&quot; alt=&quot;MiniProfiler showing all non-trivial events.&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;AJAX Tracing&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier, AJAX requests are profiled as well, to demonstrate this lets add a WebMethod to our template and a little bit of JavaScript to call it.&lt;/p&gt;
&lt;p&gt;I&#39;ve added the following WebMethod to the CodeBehind of my template, which incidentally is Default.aspx in the root of the application.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[WebMethod]
public static string Hello()
{
    using (MvcMiniProfiler.MiniProfiler.StepStatic(&quot;WebMethod Hello&quot;))
    {
        Thread.Sleep(321);
        return DataFactory.Instance.GetPage(PageReference.StartPage).PageName;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to call this from our browser, to do this I&#39;m using jQuery (from the Google CDN) and a simple ajax call. Add the following to the &amp;lt;head&amp;gt; of your template:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;text/javascript&quot;
          src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    $(function () {
        $.ajax({
            type: &quot;POST&quot;,
            url: &quot;Default.aspx/Hello&quot;,
            data: &quot;{}&quot;,
            contentType: &quot;application/json; charset=utf-8&quot;,
            dataType: &quot;json&quot;,
            success: function (msg) {
                // Replace the div&#39;s content with the page method&#39;s return value.
                $(&quot;#Result&quot;).text(&quot;AJAX: &quot; + msg.d);
            }
        });
    });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then add a div to the &amp;lt;body&amp;gt; of the page to receive the result of the AJAX call:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;Result&quot;&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Build the project and refresh the page and you should see an extra trace notification stack up in the top left corner like so:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto; border: 0px initial initial;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fMiniProfilerAJAXTab.png&quot; alt=&quot;MvcMiniProfiler tab showing AJAX request&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can inspect the profile of this AJAX request by clicking on it just like the main page request.&lt;/p&gt;
&lt;h2&gt;Next time&lt;/h2&gt;
&lt;p&gt;We haven&#39;t really touched on anything EPiServer specific here but I hope you like what you&#39;ve seen. MvcMiniProfiler is a quick and easy way to add profiling to your pages and has a really nice API in the form of IDisposable &lt;em&gt;steps&lt;/em&gt; which you use to denote sections of your page.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You can find out more about MvcMiniProfiler on the &lt;a href=&quot;http://code.google.com/p/mvc-mini-profiler/&quot; target=&quot;_blank&quot;&gt;Google Code page&lt;/a&gt;, on &lt;a href=&quot;http://marcgravell.blogspot.com/2011/06/profiling-with-knobs-on.html&quot; target=&quot;_blank&quot;&gt;Marc Gravell&#39;s blog&lt;/a&gt;, and on&amp;nbsp;&lt;a href=&quot;http://stackoverflow.com/questions/tagged/mvc-mini-profiler&quot; target=&quot;_blank&quot;&gt;Stack Overflow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next time I&#39;m going to introduce a few EPiServer-specific bits and pieces that will help you get from zero to profiled pages much quicker.&lt;/p&gt;</id><updated>2011-07-26T20:07:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>GetPropertyValue with a Default Value - PageData Extensions Method</title><link href="http://blog.gregbrant.com/post.aspx?id=4d444f60-ef61-4f02-8812-a2136137b083" /><id>&lt;p&gt;A while ago I blogged some code for &lt;a href=&quot;http://blog.gregbrant.com/post/PageData-extension-methods.aspx&quot;&gt;a couple of extension methods for the PageData type&lt;/a&gt;. An obvious addition that I&#39;ve been using for a while now but didn&#39;t cover in the first post allows you to supply the default value. This works nicely for reference types where &lt;em&gt;default(T) == null&lt;/em&gt;&amp;nbsp;and/or where you have a specific default value you want to use.&lt;/p&gt;
&lt;h2&gt;Reference Type Defaults&lt;/h2&gt;
&lt;p&gt;For reference types, the default() keyword returns a null reference and as such the previous implementation of GetPropertyValue will return null when the PageData doesn&#39;t have the property requested.&lt;/p&gt;
&lt;p&gt;Lets say we&#39;ve got a &lt;em&gt;Post&lt;/em&gt; class:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public class Post
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and we try to retrieve a property of the CurrentPage that doesn&#39;t exist:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;Post post = CurrentPage.GetPropertyValue&amp;lt;Post&amp;gt;(&quot;NonexistentProperty&quot;);
if (post == null)
    Debug.WriteLine(&quot;default(Post) == null&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This override of GetPropertyValue takes an extra argument of type T which is used as the default return value (instead of &lt;em&gt;default(T)&lt;/em&gt;):&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Gets the value of a property.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;typeparam name=&quot;T&quot;&amp;gt;The type to cast the value to.&amp;lt;/typeparam&amp;gt;
/// &amp;lt;param name=&quot;propertyName&quot;&amp;gt;The name of the property to fetch.&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&quot;defaultValue&quot;&amp;gt;The default value.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;Returns the value of the property or the suplied defaultValue.&amp;lt;/returns&amp;gt;
public static T GetPropertyValue&amp;lt;T&amp;gt;(this PageData pageData, string propertyName, T defaultValue)
{
    if(pageData == null)
        throw new ArgumentNullException(&quot;pageData&quot;);

    if(string.IsNullOrEmpty(propertyName))
        throw new ArgumentException(&quot;You must specify a property name&quot;, &quot;propertyName&quot;);

    if (pageData.Property[propertyName] != null &amp;amp;&amp;amp; 
        pageData.Property[propertyName].Value != null)
    {
        return (T)pageData.Property[propertyName].Value;
    }
    else
    {
        return defaultValue;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Value Type Defaults&lt;/h2&gt;
&lt;p&gt;All value types have a &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/25tdedf5(v=VS.100).aspx&quot;&gt;default of &lt;em&gt;zero&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2011%2f7%2fDefaultZeroForValueTypes.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For example, the default of the DateTime value type is 01/01/0001 00:00:00 and the default of int is 0.&lt;/p&gt;
&lt;p&gt;Using the version of GetPropertyValue that returns default(T) can lead to code like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;DateTime updated = CurrentPage.GetPropertyValue(&quot;LastUpdated&quot;);
if (updated == default(DateTime))
    updated = DateTime.Now;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but with this new method we can do the following and save ourselves a little more repetative code:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;DateTime updated = 
    CurrentPage.GetPropertyValue&amp;lt;DateTime&amp;gt;(&quot;LastUpdated&quot;, DateTime.Now);&lt;/code&gt;&lt;/pre&gt;</id><updated>2011-07-19T12:16:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>PageData extension methods</title><link href="http://blog.gregbrant.com/post.aspx?id=7942d578-9656-4c58-95e9-4d335bebbbaf" /><id>&lt;p&gt;Over the last two years of using EPiServer a pattern has emerged when working with a&amp;nbsp;&lt;a href=&quot;http://sdk.episerver.com/library/cms5/html/T_EPiServer_Core_PageData.htm&quot;&gt;PageData&lt;/a&gt; object in a CodeBehind file. I&#39;ve found that often, it&#39;s not enough to simply use the &amp;lt;EPiServer:Property /&amp;gt; control to display a property, sometimes you want to show or hi
&lt;script src=&quot;http://blogengine.winvps/editors/tiny_mce3/themes/advanced/langs/en.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
de an entire region (like an &amp;lt;asp:Panel /&amp;gt; or &amp;lt;asp:PlaceHolder /&amp;gt; ) 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.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://blog.gregbrant.com/image.axd?picture=2010%2f10%2ftemplate+with+header.PNG&quot; alt=&quot;Layout with image&quot; /&gt;&lt;br /&gt;Layout with header&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://blog.gregbrant.com/image.axd?picture=2010%2f10%2ftemplate+without+header.PNG&quot; alt=&quot;Layout without image&quot; /&gt;&lt;br /&gt;Layout without image&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;When accessing a property of a page that is optional, you can&#39;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:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;if (CurrentPage.Property[&quot;Foo&quot;] != null &amp;amp;&amp;amp;
    CurrentPage.Property[&quot;Foo&quot;].Value != null)
{
     // Do something
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot;&gt;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:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Gets the value of a property.
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;typeparam name=&quot;T&quot;&amp;gt;The type to cast the value to.&amp;lt;/typeparam&amp;gt;
/// &amp;lt;param name=&quot;propertyName&quot;&amp;gt;The name of the property to fetch.&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;Returns the value of the property or default(T).&amp;lt;/returns&amp;gt;
public static T GetPropertyValue&amp;lt;T&amp;gt;(this PageData me, string propertyName)
{
    if (me.Property[propertyName] != null &amp;amp;&amp;amp;
        me.Property[propertyName].Value != null)
    {
        return (T)me.Property[propertyName].Value;
    }
    else
    {
       return default(T);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which you can then use like this:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;string foo = CurrentPage.GetPropertyValue&amp;lt;string&amp;gt;(&quot;Foo&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The trouble with databinding&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ve been using that extension method in the office for around six months now; I don&#39;t think I&#39;ve accessed a property directly since, but the other day I was doing some databinding and I realised I don&#39;t like the way we usually access Properties when binding against a collection of PageData using an &amp;lt;asp:Repeater /&amp;gt;.&lt;/p&gt;
&lt;p&gt;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&#39;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?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Extending the object&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Within the &amp;lt;ItemTemplate&amp;gt;, 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.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public static T GetPropertyValue&amp;lt;T&amp;gt;(this object me, string propertyName)
{
    // try to cast the current object to PageData to access it&#39;s properties 
    PageData data = me as PageData;
    if(null == data) return default(T);
    if (data.Property[propertyName] != null &amp;amp;&amp;amp;
        data.Property[propertyName].Value != null)
    {
        return (T)data.Property[propertyName].Value;
    }
    else
    {
        return default(T);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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&#39;t like the duplication of the logic, but that&#39;s easily fixed, right. It&#39;s just a terrible idea and I&amp;nbsp;wasn&#39;t happy with the prospect but I allowed myself to continue messing around to see where I got.&lt;/p&gt;
&lt;p&gt;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 &amp;lt;%@ Import %&amp;gt; tag or in the &amp;lt;namespaces&amp;gt; tag in the web.config. I did that and I also removed the duplicated code, like so:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;namespace Application.Extensions.UI
{
    public static class PageDataExtensionsUI
    {
        public static T GetPropertyValue&amp;lt;T&amp;gt;(this object me, string propertyName)
        {
            PageData data = me as PageData;
            if(null == data) return default(T);

            return data.GetPropertyValue&amp;lt;T&amp;gt;(propertyName);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then call it on the Container.DataItem when DataBinding:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code&gt;&amp;lt;asp:Repeater runat=&quot;server&quot;&amp;gt;
    &amp;lt;ItemTemplate&amp;gt;
       &amp;lt;p&amp;gt;&amp;lt;%# Container.DataItem.GetPropertyValue(&quot;Foo&quot;) %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/ItemTemplate&amp;gt;
&amp;lt;/asp:Repeater&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This blew right up in my face wiith a big fat StackOverflowException which, it turns out, is down to &lt;a href=&quot;http://stackoverflow.com/questions/3879975/forcing-the-use-of-a-specific-overload-of-a-method-in-c&quot; target=&quot;_blank&quot;&gt;how the C# compiler resolves extension methods&lt;/a&gt;, favouring those in more local namespaces to those further afield.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;namespace Application.Extensions.UI
{
    public static class PageDataExtensionsUI
    {
        public static T GetPropertyValue&amp;lt;T&amp;gt;(this object me, string propertyName)
        {
            PageData data = me as PageData;
            if(null == data) return default(T);

            return PageDataExtensions.GetPropertyValue&amp;lt;T&amp;gt;(data, propertyName);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;In Conclusion&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I haven&#39;t done much data binding since writing this code to know how it works in practice and it hasn&#39;t spread beyond the project I implemented it to have any of the other team members run into it.&lt;/p&gt;
&lt;p&gt;I&#39;m still not entirely convinced it&#39;s the right way to go but only time will tell.&lt;/p&gt;</id><updated>2010-10-06T17:51:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>EPiServer Certified Developer #712</title><link href="http://blog.gregbrant.com/post.aspx?id=ed598f80-44cb-4f4c-8229-04cdc19115b7" /><id>&lt;p&gt;Back in July I popped down to London with a colleague, Stephen, to take the &lt;a href=&quot;http://www.episerver.com/en/Products/EPiServer-CMS-6/&quot;&gt;EPiServer CMS&lt;/a&gt; certification test which we both passed qualifying &lt;a href=&quot;http://www.twentysixdigital.com/&quot;&gt;twentysix as a Premium Solutions Partner&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;float: left; margin: 0 12px;&quot; src=&quot;http://blog.gregbrant.com/image.axd?picture=2010%2f10%2fecdlogo.png&quot; alt=&quot;EPiServer certified developer logo&quot; /&gt;Today, our certificates arrived and I&#39;m proud to say &lt;a href=&quot;http://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/?encryptedcurrentid=4lJ6NhXVQoz%2Blv7QY5JCYYFuTg7wr1hkHuNHmXqKuM4%3D&quot; target=&quot;_blank&quot;&gt;I am EPiServer Certified Developer #712&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;http://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/?encryptedcurrentid=kXuZ4tRTHu/srfi16n1iJcLcSLPaN1yVCidtdnqOAZF2/TxBPCRBUA%3D%3D&quot; target=&quot;_blank&quot;&gt;Stephen is ECD #712&lt;/a&gt;:&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: both; margin: 12px; width: auto;&quot;&gt;&lt;img src=&quot;http://blog.gregbrant.com/image.axd?picture=2010%2f10%2fEPiServer+Cert.jpg&quot; alt=&quot;My ECD Certificate&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&#39;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&#39;ve worked on some&amp;nbsp;&lt;a href=&quot;http://www.aggregate.com/&quot; target=&quot;_blank&quot;&gt;large&lt;/a&gt; and &lt;a href=&quot;http://www.gatwickairport.com/&quot; target=&quot;_blank&quot;&gt;exciting&lt;/a&gt; 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&#39;ve created two or three sites which I would call a &lt;em&gt;Standard&lt;/em&gt; build, comprising a single web and/or database server, no mirroring, no custom page providers no use of add-ons or 3&lt;sup&gt;rd&lt;/sup&gt; party integrations.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I&#39;ve also created a few sites which weren&#39;t standard,&amp;nbsp;integrating with bespoke and off-the-shelf 3&lt;sup&gt;rd&lt;/sup&gt; party systems. Mirrored and load-balanced deployments. Deployments which use SQL Server clusters and most recently, I&#39;ve written a Page Provider to integrate &lt;a href=&quot;http://www.nopcommerce.com&quot; target=&quot;_blank&quot;&gt;nopCommerce&lt;/a&gt;&amp;nbsp;into a CMS 6 site.&lt;/p&gt;
&lt;p&gt;On top of all this I&#39;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]).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tips for passing the exam&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;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&#39;t entirely agree with. It wasn&#39;t a walk in the park but it was fairly straight forward.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the Developers Guide&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I can&#39;t link you straight to it because of the funky JavaScript navigation (you can find it easily from &lt;a href=&quot;http://sdk.episerver.com/library/cms6/index.aspx&quot; target=&quot;_blank&quot;&gt;the SDK documentation&lt;/a&gt;).The developer guide is a gold mine!&lt;/p&gt;
&lt;p&gt;If there are areas EPiServer you haven&#39;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&#39;d re-read and revised all the articles in this section, some of these questions were on functionality I&#39;d never used.&lt;/p&gt;
&lt;p style=&quot;text-align: center; clear: both; margin: 12px; width: auto;&quot;&gt;&lt;img src=&quot;http://blog.gregbrant.com/image.axd?picture=2010%2f10%2fcms6+dev+guide.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the Tech Notes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Same goes for the &lt;a href=&quot;http://world.episerver.com/Documentation/Categories/Products/EPiServer-CMS/&quot; target=&quot;_blank&quot;&gt;Tech Notes&lt;/a&gt; as does the Developer Guide, read them all. The&#39;re not as long or detailed as the articles in the Dev Guide but they helped me answer a few questions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Re-read the editor and administrator manuals&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When someone is asking how to achieve something in the CMS from a user point of view, I sometimes find I&#39;m not the best person to ask, while I do Develop EPiServer sites I don&#39;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&#39;m glad I gave the &lt;a href=&quot;http://world.episerver.com/Documentation/Items/Manuals/EPiServer-CMS/Editor-Manuals---EPiServer-CMS-60/&quot; target=&quot;_blank&quot;&gt;Editor Manual&lt;/a&gt;&amp;nbsp;and the &lt;a href=&quot;http://world.episerver.com/Documentation/Items/Manuals/EPiServer-CMS/Administrator-Manuals---EPiServer-CMS-60/&quot; target=&quot;_blank&quot;&gt;Administrator Manual&lt;/a&gt; another read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the internet&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m not suggesting you read all of the internet, but if you&#39;re reading this, the chances are you&#39;ve already Googled for tips on passing the exam. Here are some that we found:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://mint.litemedia.se/2008/11/29/episerver-cms-5-certified-developer/&quot; target=&quot;_blank&quot;&gt;http://mint.litemedia.se/2008/11/29/episerver-cms-5-certified-developer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.fredrikhaglund.se/blog/2008/11/30/how-to-become-a-episerver-ceritified-developer/&quot; target=&quot;_blank&quot;&gt;http://blog.fredrikhaglund.se/blog/2008/11/30/how-to-become-a-episerver-ceritified-developer/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://robert.secondbrain.com/collection/70301/EPiServer-Certification&quot; target=&quot;_blank&quot;&gt;http://robert.secondbrain.com/collection/70301/EPiServer-Certification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/556221/does-anyone-have-any-episerver-exam-tips&quot; target=&quot;_blank&quot;&gt;http://stackoverflow.com/questions/556221/does-anyone-have-any-episerver-exam-tips&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Good luck!&lt;/p&gt;</id><updated>2010-10-05T09:40:00.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>