<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mark Everard</title>
	<atom:link href="http://www.markeverard.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.markeverard.com/blog</link>
	<description>The only consistency is change itself</description>
	<lastBuildDate>Tue, 22 May 2012 17:02:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Setting up sitewide replacement languages for EPiServer</title>
		<link>http://www.markeverard.com/blog/2012/05/22/setting-up-sitewide-replacement-languages-for-episerver/</link>
		<comments>http://www.markeverard.com/blog/2012/05/22/setting-up-sitewide-replacement-languages-for-episerver/#comments</comments>
		<pubDate>Tue, 22 May 2012 16:58:00 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=820</guid>
		<description><![CDATA[Fallback languages allow editors to specify inheritance chains for content at the page property level, meaning that if content isn&#8217;t available in the user selected language, the fallback language is served. This can be useful when working with a large site that requires a translation effort &#8211; meaning that you can translate parts of pages [...]]]></description>
			<content:encoded><![CDATA[<p>Fallback languages allow editors to specify inheritance chains for content at the page property level, meaning that if content isn&#8217;t available in the user selected language, the fallback language is served. This can be useful when working with a large site that requires a translation effort &#8211; meaning that you can translate parts of pages at a time.</p>
<p>I recently dealt with a requirement from a client who wanted to start over with their translation effort which had occurred at different rates across large areas of their site. They wanted just the English language version to be served. There are many possible solutions to this &#8211; such as putting in top-level redirects for all language variants through IIS  &#8211; however the editors wanted to retain the control of when they could re-enable a language for a particular page.</p>
<p>This meant removing all of their existing fallback and replacement languages settings for each and every page and then ensure that English was served as a replacement language for every page on every language variant*</p>
<p>* Obviously there are SEO impacts of serving <a title="How to handle multiple urls serving the same content" href="http://webmasters.stackexchange.com/questions/24922/multiple-urls-serving-same-content-how-to-handle-betterhttp://" target="_blank">identical contents on different urls,</a> our solution also included a technical piece that handled this &#8211; perhaps I&#8217;ll share that next time if anybody is interested.</p>
<h3>Under the hood</h3>
<p>EPiServer stores language replacement and fallback in the sql server table<strong> tblPageLanguageSetting</strong></p>
<p><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/05/tblPagelanguageSetting.gif"><img class="aligncenter size-full wp-image-821" title="tblPagelanguageSetting" src="http://www.markeverard.com/blog/wp-content/uploads/2012/05/tblPagelanguageSetting.gif" alt="" width="726" height="130" /></a><br />
If no data is found for a page &#8211; then the EPiServer code assumes that the fallback/replacement language data is inherited from a parent page. This behaviour is chained all the way up the tree to the site&#8217;s start page.</p>
<p>If you add data through the UI then EPiServer will add an entry to the table for each enabled language branch (in the above image I have three site languages enabled). When it does this it adds a null entry for each enabled language that doesn&#8217;t have a fallback or replacement language defined.  The presence of this entry is enough for EPiServer to know that the language data isn&#8217;t inherited.</p>
<p>So achieving our requirement is actually pretty straightforward. Ensure that the language settings are correct on the homepage and then remove all entries in this table apart from entries with <em>fkPageID</em> equal to the start page ID. (Note this wasn&#8217;t an enterprise scenario &#8211; you may have to be a little more granular with what you delete in that instance)</p>
<p>Obviously running direct SQL against the EPiServer schema isn&#8217;t recommended (or supported by EPiServer) &#8211; so <strong>BE CAREFUL</strong> &#8211; with great power comes great responsibility. However this is a huge time-saver over using the UI to achieve the same result.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/05/22/setting-up-sitewide-replacement-languages-for-episerver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Will HTML5 deliver the mobile app-ocalypse?</title>
		<link>http://www.markeverard.com/blog/2012/05/16/will-html5-deliver-the-mobile-app-ocalypse/</link>
		<comments>http://www.markeverard.com/blog/2012/05/16/will-html5-deliver-the-mobile-app-ocalypse/#comments</comments>
		<pubDate>Wed, 16 May 2012 13:02:31 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=779</guid>
		<description><![CDATA[Despite the continued success of Apples&#8217; App Store and similar online application stores, publishers are beginning to invest and deliver mobile applications using technologies that many believe may signal the demise of the traditional native app. Is it time to take shelter from an impending mobile app-ocalypse? With the current popularity of the App Store [...]]]></description>
			<content:encoded><![CDATA[<p>Despite the continued success of Apples&#8217; App Store and similar online application stores, publishers are beginning to invest and deliver mobile applications using technologies that many believe may signal the demise of the traditional native app. Is it time to take shelter from an impending mobile app-ocalypse?</p>
<p>With the current popularity of the App Store (over 25 billion downloads) it might not seem like it. However the phenomenal success of the native app market presents a number of problems for both users and publishers alike.</p>
<p style="text-align: center;"><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/05/app-ocolypse.png"><img class=" wp-image-798 aligncenter" title="Will HTML5 deliver the mobile app-ocalypse?" src="http://www.markeverard.com/blog/wp-content/uploads/2012/05/app-ocolypse.png" alt="Will HTML5 deliver the mobile app-ocalypse?" width="273" height="254" /></a></p>
<h2></h2>
<p><strong>The App Store is noisy</strong></p>
<p>There are now over 500,000 apps available on the App Store meaning that finding the latest and greatest is difficult. This can lead to a unhealthy reliance on curated lists and editorially featured content as a means to reliably discover new apps.</p>
<p>As a publisher, this increases the risk that your beautifully created app can sink without trace, no matter how great it really is. This increased competition in the market place also brings out the more <a title="App Developers Resort to Buying Good Reviews" href="http://appstoreoptimize.com/app-developers-resort-to-buying-good-reviews/" target="_blank">nefarious means of grabbing attention</a>. Those user reviews and 5-star ratings are worth real money!</p>
<p><strong>Mobile home screens are overcrowded</strong></p>
<p>Once you&#8217;ve found and downloaded the app you want, it has to compete with all of the other apps you&#8217;ve downloaded for prime real estate on your device&#8217;s home screen. The desktop paradigm that most devices have adopted just doesn&#8217;t scale to hundreds of apps. The cost of having to organise, rearrange, update and de-clutter your home screen becomes significant compared to the individual value offered by many of the apps.</p>
<p><strong>Developing for multiple platforms is expensive</strong></p>
<p>Which platforms should you launch your app on? How many versions built on different platforms can your development teams support? Should you try and develop features in parallel across platforms or should you let your feature set diverge and add new features to one platform first? All difficult decisions. It&#8217;s pretty clear why there is an imperative to develop with cross-platform mobile frameworks.</p>
<h2>Is HTML5 the answer?</h2>
<p>No, not in isolation. HTML5 is often misunderstood. It provides an open standards way of marking up data for display as  user interfaces, content and rich media. So the real question is will web apps using HTML5 become the dominant way of delivering mobile functionality? The answer as always lies in the <a title="Tim Bray - Browsers vs Apps" href="http://www.tbray.org/ongoing/When/201x/2012/05/02/Web-Futurez" target="_blank">context</a>. If you need to interact with the device hardware then a native app is still the best way to achieve this. If you need to present content, text, images and media then HTML5 and a web app allows you to do this in a cost effective and time-tested way.</p>
<p>There is a third way. Many publishers are now pushing a hybrid approach and realising significant cost savings across mobile channels by building native apps which use HTML5 to deliver user interfaces that are imperceivably different to those offered by native code. Take for example, the <a title="You’ll never believe how LinkedIn built its new iPad app" href="http://venturebeat.com/2012/05/02/linkedin-ipad-app-engineering/" target="_blank">latest LinkedIn IPad app</a> which to many commentator&#8217;s surprise delivers 95% of it&#8217;s views using HTML5 (and of course a hefty dose of JavaScript and server-side data services).</p>
<p><strong>Apps-on-demand</strong></p>
<p>Native apps won&#8217;t disappear but clearly there is convergence between the experiences native apps can deliver and those available via a browser.</p>
<p>Perhaps though it&#8217;s the app delivery mechanism that will change most of all. Rather than investing time up-front collecting apps from a store (with a vastly <a title="Apple Acquires Chomp; App Store Search And Discovery To Be Completely Revamped" href="http://techcrunch.com/2012/02/23/apple-chomp/" target="_blank">improved app discovery mechanism</a>), perhaps apps will be downloaded only if and when you need them. This is the exact model suggested by ex-Apple and Google mobile UX guru <a title="Scott Jenson on Twitter" href="http://twitter.com/scottjenson/" target="_blank">Scott Jenson</a> who suggests that <a title="Mobile Apps Must Die" href="http://designmind.frogdesign.com/blog/mobile-apps-must-die.html" target="_blank">future apps will be delivered &#8216;just-in-time&#8217;</a>, installing only the features you need there and then. The underlying technology for such delivery is already available. It&#8217;s the web!</p>
<h2>Here for the long run</h2>
<p>Ultimately, reports on the death of native mobile apps have been greatly exaggerated, but HTML5 shows every sign of becoming the dominant cross-platform technology for serving rich interfaces, media and content.</p>
<p>Every future device of note will have a standards compliant browser, meaning that every device will be capable of consuming content and services delivered in HTML. As a publisher or developer it would be foolish to ignore this. As a user, hopefully you won&#8217;t even notice the difference&#8230;..</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/05/16/will-html5-deliver-the-mobile-app-ocalypse/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>This time&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;.</title>
		<link>http://www.markeverard.com/blog/2012/04/18/this-time/</link>
		<comments>http://www.markeverard.com/blog/2012/04/18/this-time/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 11:10:48 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Opinion]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=773</guid>
		<description><![CDATA[This isn&#8217;t mine &#8211; in fact I don&#8217;t know who the credit should go to. However, it was so great I wanted to put it somewhere relevant where I could see it often. UPDATE (16th May 2012): It originally came Manu Cornet at Bonkers World. Awesome stuff &#160; &#160;]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/04/jMHoE.jpg"><img class="aligncenter  wp-image-774" title="This time" src="http://www.markeverard.com/blog/wp-content/uploads/2012/04/jMHoE.jpg" alt="This time" width="672" height="511" /></a></p>
<p>This isn&#8217;t mine &#8211; in fact I don&#8217;t know who the credit should go to. However, it was so great I wanted to put it somewhere relevant where I could see it often.</p>
<p><strong>UPDATE</strong> (16th May 2012): It originally came Manu Cornet at <a title="Bonkers World" href="http://www.bonkersworld.net/">Bonkers World</a>. Awesome stuff</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/04/18/this-time/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Personalize your EPiServer site by visit duration</title>
		<link>http://www.markeverard.com/blog/2012/04/17/personalize-your-episerver-site-by-visit-duration/</link>
		<comments>http://www.markeverard.com/blog/2012/04/17/personalize-your-episerver-site-by-visit-duration/#comments</comments>
		<pubDate>Tue, 17 Apr 2012 07:00:46 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=723</guid>
		<description><![CDATA[Want to show a personalized message of gratitude to those users who spend a long time on your site? Now you can with the TimeOnSiteCriterion for the EPiServer Personalization/Visitor Group framework Technically &#8211; this is a straightforward implementation of a Visitor Group criteria, using some of the native Personalization API to record when the user [...]]]></description>
			<content:encoded><![CDATA[<p>Want to show a personalized message of gratitude to those users who spend a long time on your site? Now you can with the TimeOnSiteCriterion for the EPiServer Personalization/Visitor Group framework <img src='http://www.markeverard.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Technically &#8211; this is a straightforward implementation of a Visitor Group criteria, using some of the native Personalization API to record when the user starts their session. This is then compared to the current DateTime along with the editor selected time period to calculate a match.</p>
<p style="text-align: center;"><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/04/timeonsitecriterion.png"><img class="aligncenter  wp-image-722" title="timeonsitecriterion" src="http://www.markeverard.com/blog/wp-content/uploads/2012/04/timeonsitecriterion.png" alt="" width="560" height="190" /></a></p>
<p>The TimeOnSiteCriterion is available as part of Criteria Pack version 1.3, which is available <a title="Criteria pack for EPiServer" href="http://criteriapack.codeplex.com/" target="_blank">on Codeplex</a> (along with the source code) and of course there is an individual Nuget package on <a title="EPiServer Nuget feed" href="http://nuget.episerver.com/" target="_blank">Nuget.episerver.com</a></p>
<h2>An Extended example</h2>
<p>One of the clients I&#8217;m working with at the minute had a requirement to display a modal pop-up on their site to user&#8217;s who had either visited a set number of pages, or had visited for more than a defined duration. Using the Visitor Group functionality sounded like a good match as it allows the editor&#8217;s to specify the exact criteria and mix and match with other matching criteria moving forwards.</p>
<p>The TimeOnSite criterion obviously forms part of this requirement, but fully meeting the requirement involves not waiting for a user to request a new page from your site and instead delegating responsibility to the browser to continue the countdown and respond (display the popup) when the criteria is matched. This is a requirement that the Visitor Group API doesn&#8217;t handle completely, as a Visitor Group is resolved as either a match or not a match when the page is delivered to the browser. There is no straightforward way of working out how &#8216;much&#8217; of a match the current request may be.</p>
<p>Never the less, we still have the flexibility to achieve this:</p>
<ol>
<li>We need to link the site to a specific Visitor Group that will provide our criteria for when to display the popup (using a custom property like <a title="Visitor Group Custom Property" href="http://world.episerver.com/Blogs/Thomas-Krantz-/Dates/2011/4/Custom-property-for-selecting-Visitor-Groups/" target="_blank">this</a> will do the job &#8211; possibly on a site wide settings page)</li>
<li>We need a method of working out how close we are to a match being made &#8211; in this case how many seconds are left. This data needs to be delivered to the browser.</li>
<li>We need some client side script that will continue the countdown and trigger the popup when the countdown reaches zero.</li>
</ol>
<p>The following public class is a part of the TimeOnSiteCriterion assembly, and contains the SecondsToMatch method to which can be used to work out how many seconds remain. The method will search a single Visitor Group &#8211; which is instantiated by Id (which is why we need a custom property to store this information), to find the first instance of a TimeOnSite model. This model contains the editor selected TimeOnSite criterion &#8211; which is then used with the user&#8217;s session start variable to calculate how long remains.</p>
<pre class="brush: csharp; title: ; notranslate">

using System;
using System.Linq;
using System.Web;
using EPiServer.Personalization.VisitorGroups;

namespace CriteriaPack.TimeOnSiteCriterion
{
    public class TimeOnSiteService
    {
        public TimeOnSiteService()
        {
            Store = new VisitorGroupStore();
        }

        public TimeOnSiteService(IVisitorGroupRepository store)
        {
            Store = store;
        }

        public IVisitorGroupRepository Store { get; set; }

        private double CurrentValueInSeconds(Guid visitorGroupId)
        {
            //load visitor group by providing id
            var group = Store.Load(visitorGroupId);
            if (group == null)
                return 0;

            //return first instance of TimeOnSite Criterion
            var timeOnSiteCriteria = group.Criteria.FirstOrDefault(a =&gt; a.TypeName == VisitorGroupCriterionRepository.GetTypeName(typeof(TimeOnSiteCriterion)));
            if (timeOnSiteCriteria == null)
                return 0;

            var model = timeOnSiteCriteria.Model as TimeOnSiteModel;
            if (model == null)
                return 0;

            if (model.DurationUnit == DurationUnit.Minutes)
                return model.TimeOnSite * 60;

            if (model.DurationUnit == DurationUnit.Hours)
                return model.TimeOnSite * 60 * 60;

            return model.TimeOnSite;
        }

        private DateTime SessionStart(HttpContextBase httpContext)
        {
            return Convert.ToDateTime(httpContext.Session[TimeOnSiteCriterion.SessionStartTimeKey]);
        }

        /// &lt;summary&gt;
        /// Returns the number of seconds remaining until a match.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;httpContext&quot;&gt;The HTTP context.&lt;/param&gt;
        /// &lt;param name=&quot;visitorGroupId&quot;&gt;The visitor group id.&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public double SecondsToMatch(HttpContextBase httpContext, Guid visitorGroupId)
        {
            var matchTime = SessionStart(httpContext);
            matchTime = matchTime.AddSeconds(CurrentValueInSeconds(visitorGroupId));

            double timeToMatch = (matchTime - DateTime.Now).TotalSeconds;
            return timeToMatch &lt; 0
                ? 0
                : timeToMatch;
        }
    }
}
</pre>
<p>The final part is to use this in a page:</p>
<pre class="brush: csharp; title: ; notranslate">

   protected void Page_Load(object sender, EventArgs e)
   {
      var service = new TimeOnSiteService();

      //retrieve this from a page / sitewide property - allowing match from the page to the time tracking visitor group
      var visitorGroupId = new Guid(&quot;4c3bb8b2-4e8e-4fbc-bc24-5018e8c935af&quot;);

      //use the TimeOnSiteService to return the number of seconds to match
      double timeToLive = service.SecondsToMatch(new HttpContextWrapper(HttpContext.Current), visitorGroupId);
      //convert to milliseconds and write to the page
      TimeToLive.Text = (timeToLive *1000).ToString();
   }
</pre>
<p>and then write some javascript to handle this (also perhaps write it slightly better than below. Hey I&#8217;m no javascript developer &#8211; yet!)</p>
<pre class="brush: jscript; title: ; notranslate">

  &lt;script type=&quot;text/javascript&quot;&gt;

        function setAlertTimeOut() {
          var timeToLive = '&lt;asp:Literal id=&quot;TimeToLive&quot; runat=&quot;server&quot; /&gt;';
          if (timeToLive &gt; 0) {
              setTimeout('AlertMe()', timeToLive);
          }
        }

        function AlertMe() {
            alert(&quot;Time is Up&quot;);
        }

    &lt;/script&gt;
</pre>
<p>and also don&#8217;t forget to call the method setAlertTimeOut() when the browser loads your page. I&#8217;d also imagine that your front end will need to do something a little more fancy than pop up an alert&#8230;&#8230;&#8230;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/04/17/personalize-your-episerver-site-by-visit-duration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Page Type security overview plugin for EPiServer</title>
		<link>http://www.markeverard.com/blog/2012/04/12/a-page-type-security-overview-plugin-for-episerver/</link>
		<comments>http://www.markeverard.com/blog/2012/04/12/a-page-type-security-overview-plugin-for-episerver/#comments</comments>
		<pubDate>Thu, 12 Apr 2012 11:00:01 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=736</guid>
		<description><![CDATA[I&#8217;ve been dealing with more of EPiServer&#8217;s security and access control functionality recently. See my recent post about creating an attribute based framework for managing security at the property level as a example. When it comes to enterprise level security requirements,  governance is the key. This means not just having the ability to define your  [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been dealing with more of EPiServer&#8217;s security and access control functionality recently. See my recent post about creating an attribute based framework for <a title="Role and user based property security for EPiServer " href="http://www.markeverard.com/blog/2012/02/13/role-and-user-based-property-security-for-episerver/" target="_blank">managing security at the property level</a> as a example.</p>
<p>When it comes to enterprise level security requirements,  governance is the key. This means not just having the ability to define your  security policy (through an admin panel for example) but also having a current and clear overview of your security setup.</p>
<p>Whilst EPiServer provides this for the creating page functionality (Set Access Rights page and the page-tree), it doesn&#8217;t offer this for Page Types. Certainly this is something we can improve upon so I&#8217;ve put together a simple Admin Plugin (<a title="Creating EpiServer Plugins using MVC" href="http://world.episerver.com/Blogs/Paul-Smith/Dates1/2011/8/Creating-EPiServer-AdminEdit-Plug-ins-using-MVC/" target="_blank">built using MVC</a> &#8211; why would you use anything else these days?)</p>
<p>The plugin lists each Page Type, whether it is available in edit mode, the users and roles who can create pages of that page type and also the allowable child page types for that page type.</p>
<p>A Nuget package (FortuneCookie.PageTypeSecurityOverview) built against EPiServer 6R2 is available from the <a title="EPiServer Nuget" href="http://nuget.episerver.com/" target="_blank">EPiServer Nuget feed</a>. The source code is available on<a title="FortuneCookie.PageTypeSecurityOverview on GitHub" href="https://github.com/markeverard/FortuneCookie.PageTypeSecurityOverview" target="_blank"> GitHub – https://github.com/markeverard/FortuneCookie.PageTypeSecurityOverview</a></p>
<p>&nbsp;</p>
<p><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/04/pagetypesecurityoverview.png"><img class="aligncenter size-full wp-image-737" title="Page Type Security Overview" src="http://www.markeverard.com/blog/wp-content/uploads/2012/04/pagetypesecurityoverview.png" alt="Page Type Security Overview" width="700" height="463" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/04/12/a-page-type-security-overview-plugin-for-episerver/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>FortuneCookie.PropertySecurity version 2.0</title>
		<link>http://www.markeverard.com/blog/2012/04/10/fortunecookie-propertysecurity-version-2-0/</link>
		<comments>http://www.markeverard.com/blog/2012/04/10/fortunecookie-propertysecurity-version-2-0/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 09:00:03 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=746</guid>
		<description><![CDATA[The coding machine that is Lee Crowe and myself have made a few additional changes to the PropertySecurity attribute framework I blogged about a few weeks ago. The changes in Version 2.0 are: It&#8217;s now absolutely dependent on PTB2 &#8211; you&#8217;ll see why below. PropertySecurity attributes can now be applied to PropertyGroups &#8211; this is [...]]]></description>
			<content:encoded><![CDATA[<p>The coding machine that is <a title="Lee Crowe on EPiServer World" href="http://world.episerver.com/System/Users-and-profiles/Community-Profile-Card/Croweman/" target="_blank">Lee Crowe</a> and myself have made a few additional changes to the <a title="Role and user based property security for EPiServer" href="http://www.markeverard.com/blog/2012/02/13/role-and-user-based-property-security-for-episerver/" target="_blank">PropertySecurity attribute framework</a> I blogged about a few weeks ago.</p>
<p><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/04/bpi75.jpg"><img class="wp-image-750 aligncenter" title="Security" src="http://www.markeverard.com/blog/wp-content/uploads/2012/04/bpi75.jpg" alt="" width="360" height="240" /></a></p>
<p>The changes in Version 2.0 are:</p>
<ol>
<li>It&#8217;s now absolutely dependent on PTB2 &#8211; you&#8217;ll see why below.</li>
<li>PropertySecurity attributes can now be applied to PropertyGroups &#8211; this is why we need PTB2. You can now add a class level definition to a PropertyGroup definition</li>
<li>PropertySecurity Attributes can now be applied to Tab class definitions &#8211; providing a shortcut to more granular management of property security.</li>
<li>The ApplyToDefaultProperties functionality has been removed &#8211; this created some problems with the required validation settings &#8211; meaning it was possible to publish phantom pages with incomplete information.</li>
</ol>
<p>The following hierarchical rules apply to attributes:</p>
<ul>
<li>A property level [Authorize] attribute in a PropertyGroup will override any other setting</li>
<li>A property level [Authorize] attribute not on a PropertyGroup in a TypedPageData class  will tabs or class level settings</li>
<li>An [Authorize] attribute on a tab will be honoured next and take preference over a class level setting</li>
<li>A class level [Authorize] attribute on a tab will take preference only if the above aren&#8217;t matched</li>
</ul>
<p title="EPiServer Nuget">An updated Nuget package (FortuneCookie.PropertySecurity) built against .Net 4.0 / EPiServer 6R2 and PTB 2.0 is available <a title="EPiServer Nuget" href="http://nuget.episerver.com/" target="_blank">EPiServer Nuget feed</a>. The source code is available on <a title="FortuneCookie.PropertySecurity source code at GitHub" href="https://github.com/markeverard/FortuneCookie.PropertySecurity" target="_blank">GitHub – https://github.com/markeverard/FortuneCookie.PropertySecurity</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/04/10/fortunecookie-propertysecurity-version-2-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Role and user based property security for EPiServer</title>
		<link>http://www.markeverard.com/blog/2012/02/13/role-and-user-based-property-security-for-episerver/</link>
		<comments>http://www.markeverard.com/blog/2012/02/13/role-and-user-based-property-security-for-episerver/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 07:00:59 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=701</guid>
		<description><![CDATA[One of the requirements I&#8217;ve often seen from some of our bigger (more enterprise) EPiServer clients &#8211; is the ability to add more granular levels of security to the page editing process. By default EPiServer allows the following security to be set up for page editing: Specify edit / admin rights for each page &#8211; [...]]]></description>
			<content:encoded><![CDATA[<p>One of the requirements I&#8217;ve often seen from some of our bigger (more enterprise) EPiServer clients &#8211; is the ability to add more granular levels of security to the page editing process. By default EPiServer allows the following security to be set up for page editing:</p>
<ul>
<li><strong>Specify edit / admin rights for each page</strong> &#8211; this allows you to define parts of the page tree that editors have permissions over. These permissions allow you to use the to specify one of the following access levels for each page (Read / Create / Change/ Delete / Publish / Administer) which dictates an editor&#8217;s ability to create / view and publish a page.</li>
<li><strong>Specify access levels required to view each edit mode tab</strong> &#8211; this allows you to group particular page properties onto particular tabs and show or hide those based on the access levels defined above.</li>
</ul>
<p>However &#8211; what is missing here is a more granular approach for individual properties on each page. For example allowing users in a &#8216;MetaEditor&#8217; role to update page meta data without being able to edit anything else.</p>
<p>EPiServer exposes an EditPanel.LoadedPage event which allows you to modify the loaded PageData object and modify it accordingly. One of the code properties available on an EPiServer property is DisplayEditUI which dictates whether the property is shown on the edit panel. Using the EditPanel.LoadedPage event to set property visibility in this way <a title="Hiding properties in edit mode " href="http://world.episerver.com/Modules/Forum/Pages/thread.aspx?id=41592" target="_blank">isn&#8217;t new</a>.  However now we have strongly typed PageType classes (thanks to <a title="EPiServer CMS PageTypeBuilder" href="http://pagetypebuilder.codeplex.com/" target="_blank">PageTypeBuilder</a>) we can revisit this and treat it as a true application cross cutting concern.</p>
<p>What I wanted to be able to achieve was a true attribute based security system, that worked with the standard ASP.Net Membership model allowing developers to set which roles and users would be able to view and modify each property by setting an code based attribute in the TypedPageData class.</p>
<p>The solution relies on the following pieces:</p>
<ul>
<li>An EPiServer Initialization module that hooks up a method to the EditPanel.LoadedPage event.</li>
<li>An Authorize attribute that you can place on PageTypeBuilder TypedPageData classes and properties.</li>
<li>A locator which will scan your current page type for each property and modify the DisplayEditUI property based on the attributes values.</li>
</ul>
<p>The following rules apply:</p>
<ul>
<li>A property level [Authorize] attribute will override any setting from a class level [Authorize] attribute</li>
<li>[Authorize] attributes can set either usernames or roles which will be honoured &#8211; see the example below.</li>
<li>The [Authorize] attribute allows you to specify whether you wish to apply the security rules to the built in-EPiServer properties as well as any you have defined through code.</li>
</ul>
<p>Here is an example usage:</p>
<pre class="brush: csharp; title: ; notranslate">
using System;
using FortuneCookie.PropertySecurity;
using PageTypeBuilder;
using EPiServer.Templates.AlloyTech.PageTypes.Tabs;

namespace EPiServer.Templates.AlloyTech.PageTypes.AlloyTech
{
   [PageType(&quot;74f6ef3e-407b-4132-8108-7fa831910197&quot;,
   Name = &quot;[AlloyTech] Standard page&quot;,
   Filename = &quot;/Templates/AlloyTech/Pages/Page.aspx&quot;,
   DefaultChildSortOrder = EPiServer.Filters.FilterSortOrder.None,
   Description = &quot;The standard page is the most commonly used page on the web site.&quot;,
   DefaultVisibleInMenu = true,
   AvailablePageTypes = new Type[] {  })]
   [Authorize(Principals = &quot;StandardPageEditorRole,mark.everard&quot;, ApplyToDefaultProperties = false)]
   public class StandardpagePageType : TypedPageData
   {
      [PageTypeProperty(EditCaption = &quot;Main body&quot;,
      HelpText = &quot;The main body will be shown in the main content area of the page&quot;,
      Tab = typeof(InformationTab),
      Type = typeof(EPiServer.SpecializedProperties.PropertyXhtmlString))]
      [Authorize(Principals = &quot;MainBodyEditorRole&quot;)]
      public virtual string MainBody { get; set; }

      [PageTypeProperty(EditCaption = &quot;Secondary body&quot;,
      HelpText = &quot;The contents of this property will be shown in the right column of the page, you can use both text and images for layout.&quot;,
      Tab = typeof(InformationTab),
      Type = typeof(EPiServer.SpecializedProperties.PropertyXhtmlString))]
      public virtual string SecondaryBody { get; set; }
   }
}
</pre>
<p>In this case &#8211; any editor will be able to see the default EPiServer page properties (PageName, PageCategories etc). Editors in the StandardPageEditorRoles and me (user with username mark.everard) will be able to view / edit the SecondaryBody property, and only editors in the MainBodyEditorRole will be able to modify the MainBody property.</p>
<p>At present,  I&#8217;m not too happy with the blanket approach to the default properties that the current version has. I&#8217;d be interested to hear any better ideas for dealing with this &#8211; or better yet send me a pull request to the <a title="FortuneCookie.PropertySecurity source code at GitHub" href="https://github.com/markeverard/FortuneCookie.PropertySecurity" target="_blank">project on GitHub</a>.</p>
<p>A Nuget package (FortuneCookie.PropertySecurity) built against .Net 4.0 / EPiServer 6R2 and PTB 2.0 has been uploaded for review to the <a title="EPiServer Nuget" href="http://nuget.episerver.com" target="_blank">EPiServer Nuget feed</a> (and so should be available soon). The source code is available on <a title="FortuneCookie.PropertySecurity source code at GitHub" href="https://github.com/markeverard/FortuneCookie.PropertySecurity" target="_blank">GitHub &#8211; https://github.com/markeverard/FortuneCookie.PropertySecurity</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/02/13/role-and-user-based-property-security-for-episerver/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>London EPiServer Meetup is on 23rd Feb</title>
		<link>http://www.markeverard.com/blog/2012/02/02/london-episerver-meetup-is-on-23rd-feb/</link>
		<comments>http://www.markeverard.com/blog/2012/02/02/london-episerver-meetup-is-on-23rd-feb/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 13:12:04 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Community]]></category>
		<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=693</guid>
		<description><![CDATA[We&#8217;re back for 2012. We&#8217;ll be having our first 2012 London EPiServer Developer Meetup, hosted at Fortune Cookie on Thursday 23rd February. Coming to talk to us this time will be: Meridium &#8211; who will be telling us all about the latest version of ImageVault &#8211; which is image and digital asset management module for [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re back for 2012. We&#8217;ll be having our first 2012 <a title="EPiServer developers in London" href="http://www.meetup.com/EPiServer-London/" target="_blank">London EPiServer Developer Meetup</a>, hosted at <a title="Digital Agency London" href="http://www.fortunecookie.co.uk" target="_blank">Fortune Cookie</a> on <strong>Thursday 23rd February.</strong></p>
<p><strong></strong>Coming to talk to us this time will be:</p>
<ul>
<li><a title="Meridium develop and distribute unique off the shelf add-on's for EPiServer and Microsoft SharePoint, resulting in a more powerful, efficient and easy to use plattform. " href="http://www.meridium.se/en/" target="_blank">Meridium</a> &#8211; who will be telling us all about the latest version of <a title="ImageVault" href="http://www.meridium.se/en/products/imagevault/overview/" target="_blank">ImageVault</a> &#8211; which is image and digital asset management module for EPiServer.</li>
<li><a title="Joel Abrahamsson" href="http://joelabrahamsson.com/" target="_blank">Joel Abrahamsson</a> &#8211; who should need little introduction. Joel has been instrumental in helping to improve the EPiServer development experience &#8211; through his open source projects such as <a title="Page Type Builder for EPiServer CMS" href="http://pagetypebuilder.codeplex.com/" target="_blank">PageTypeBuilder</a> and <a title="EPiAbstractions" href="http://epiabstractions.codeplex.com/" target="_blank">EPiAbstractions</a> (amongst others). Tonight though Joel will be wearing a different hat as he&#8217;ll be talking about his latest project. <a title="Truffler - an advanced search engine service" href="http://truffler.net/" target="_blank">Truffler.Net</a> &#8211; an advanced search engine and C# API</li>
<li>Plus &#8211; some other (to be confirmed) talks from our community members</li>
</ul>
<p>We will start <strong>presentations promptly at 7pm</strong> so please aim to get there for <strong>6:30pm</strong></p>
<p>There will be some food and drinks (kindly provided by <a title="EPiServer - software to build your online presence" href="http://www.episerver.com/" target="_blank">EPiServer</a> UK) and plenty of opportunity to network and talk tech.</p>
<p><a title="EPiServer Developer Meetup Spring 2012" href="http://www.meetup.com/EPiServer-London/events/50703712/" target="_blank">Full details are on the Meetup page</a> where you can sign up and RSVP to confirm attendance.</p>
<p>I hope you&#8217;ll agree that its a great program and also I think we&#8217;re incredibly lucky to have both Meridium and Joel flying over from Sweden to come and talk to us. Please show your support.</p>
<p>See you all on the 23rd.</p>
<p>Mark</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/02/02/london-episerver-meetup-is-on-23rd-feb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Missing Personalization Containers</title>
		<link>http://www.markeverard.com/blog/2012/01/06/missing-personalization-containers/</link>
		<comments>http://www.markeverard.com/blog/2012/01/06/missing-personalization-containers/#comments</comments>
		<pubDate>Fri, 06 Jan 2012 16:00:36 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/?p=673</guid>
		<description><![CDATA[Combining Composer with Visitor groups on your EPiServer CMS6 R2 site gives your editors a powerful new way of working with &#8216;personalized&#8217; content, via the built-in Personalization Container Composer element. This function allows an editor to create a Composer area that will display a unique list of other Composer functions; depending on which visitor group [...]]]></description>
			<content:encoded><![CDATA[<p>Combining Composer with Visitor groups on your EPiServer CMS6 R2 site gives your editors a powerful new way of working with &#8216;personalized&#8217; content, via the built-in Personalization Container Composer element.</p>
<p>This function allows an editor to create a Composer area that will display a unique list of other Composer functions; depending on which visitor group a user is matched to in your site. This means that editors can personalise more than just page content, and can also adjust the page layout and functionality offered to each visitor, by dragging different Composer functions into each Personalized &#8216;slide&#8217; within the Personalization Container function.</p>
<h2>Upgrading a site to 6 R2</h2>
<p>After upgrading a few sites from CMS6 to CMS6R2, if you don&#8217;t check the option to import PageTypes during the upgrade process (which if you&#8217;re using PageTypeBuilder you might think you can skip) then  the Personalization container isn&#8217;t created, and you&#8217;ll be missing this piece of functionality.</p>
<p style="text-align: center;"><a href="http://www.markeverard.com/blog/wp-content/uploads/2012/01/personalizationcontainer11.png"><img class="size-full wp-image-681 aligncenter" title="personalization container" src="http://www.markeverard.com/blog/wp-content/uploads/2012/01/personalizationcontainer11.png" alt="personalization container" width="500" /></a></p>
<p>The easiest way to re-create this function is to export the composer PageType information from a &#8216;fresh&#8217; install of the Composer / R2 Alloy Tech site, and then import this into your site.</p>
<p>To save you the hassle of setting up a fresh demo site. I&#8217;ve included an exported Composer Personalization function as a download below (.xml format).</p>
<p><a title="Personalization Container" href="http://www.markeverard.com/blog/wp-content/uploads/2012/01/PersonalizationContainer1.zip" target="_blank">PersonalizationContainer.zip</a> &#8211; Import using EPiServer Composer Import / Export page.</p>
<p>You just need to import this using the Composer import feature in EPiServer Admin mode, and hey presto!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2012/01/06/missing-personalization-containers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A QueryString Visitor Group Criterion for EPiServer</title>
		<link>http://www.markeverard.com/blog/2011/11/07/a-querystring-visitor-group-criterion-for-episerver/</link>
		<comments>http://www.markeverard.com/blog/2011/11/07/a-querystring-visitor-group-criterion-for-episerver/#comments</comments>
		<pubDate>Mon, 07 Nov 2011 08:00:11 +0000</pubDate>
		<dc:creator>Mark</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[EPiServer]]></category>

		<guid isPermaLink="false">http://www.markeverard.com/blog/2011/11/28/query-string/</guid>
		<description><![CDATA[A common usage for advanced website analytics systems (Omniture, Google etc) is to track the effectiveness of external digital marketing campaigns such as banner ads, pay-per-click, sponsored search results&#8230;&#8230;.. Technically, this is normally achieved by adding a querystring key to the campaign link url and then tracking requests that use this key. So for example, [...]]]></description>
			<content:encoded><![CDATA[<p>A common usage for advanced website analytics systems (Omniture, Google etc) is to track the effectiveness of external digital marketing campaigns such as banner ads, pay-per-click, sponsored search results&#8230;&#8230;..</p>
<p>Technically, this is normally achieved by adding a querystring key to the campaign link url and then tracking requests that use this key. So for example, a Google Adwords campaign linking to your /products page would also include a querystring parameter of cid=marketingcampaign (example: http://yoursite.com/products?cid=marketingcampaign)</p>
<p>This querystring parameter can be picked up by your analytics implementation and used to track various aspects of the campaign.</p>
<p>On an EPiServer CMS6 R2 site, editors can use the Personalization/Visitor Group framework to provide a unique page experience per visitor, meaning that its possible to provide personalized content for each external marketing campaign on any page on your site.</p>
<p>Out-of-the-box, EPiServer provides a criterion which checks the incoming request Url or the page referrer, but not one that checks the querystring of the incoming request.</p>
<p>Creating a Visitor group criterion is <a title="Developing Custom Visitor Group Criteria" href="http://world.episerver.com/Documentation/Items/Tech-Notes/EPiServer-CMS-6/EPiServer-CMS-6-R2/Visitor-Groups-Creating-Custom-Criteria/" target="_blank">straight forward</a> &#8211; the only issue I&#8217;ve ever had trouble with; is when working on a .NET 4.0 project &#8211; <a title="Unable to implement abstract CriterionBase class in EPiServer " href="http://tedgustaf.com/en/blog/2011/4/criterionbase-no-suitable-method-found-to-override/" target="_blank">which was solved by Ted Nyberg.</a></p>
<p>I&#8217;ve created a simple QueryString Criterion which will provide a match based on the following:</p>
<ol>
<li>Whether the current request contains a user specified querystring key</li>
<li>and / or whether the current request contains a matching querystring key which also has the user specified value.</li>
</ol>
<p style="text-align: center;"><a href="http://www.markeverard.com/blog/wp-content/uploads/2011/11/querystringcriterion.png"><img class="aligncenter size-full wp-image-664" title="querystringcriterion" src="http://www.markeverard.com/blog/wp-content/uploads/2011/11/querystringcriterion.png" alt="" width="600" height="326" /></a></p>
<p>The source code is available as part of the <a title="Criteria Pack for EPiServer CMS on CodePlex" href="http://criteriapack.codeplex.com/" target="_blank">Criteria Pack on Codeplex</a> and of course there is a Nuget package on <a title="EPiServer Nuget feed" href="http://nuget.episerver.com/" target="_blank">Nuget.episerver.com</a> &#8211; (as soon as its been approved!)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.markeverard.com/blog/2011/11/07/a-querystring-visitor-group-criterion-for-episerver/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

