Mark Everard

Hello, I'm Mark – a PhD physicist turned technologist / architect.

Archive for April, 2012

This time……………….

without comments

This time

This isn’t mine – in fact I don’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

 

 

Written by mark

April 18th, 2012 at 2:10 pm

Posted in Opinion

Personalize your EPiServer site by visit duration

without comments

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 – 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.

The TimeOnSiteCriterion is available as part of Criteria Pack version 1.3, which is available on Codeplex (along with the source code) and of course there is an individual Nuget package on Nuget.episerver.com

An Extended example

One of the clients I’m working with at the minute had a requirement to display a modal pop-up on their site to user’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’s to specify the exact criteria and mix and match with other matching criteria moving forwards.

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’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 ‘much’ of a match the current request may be.

Never the less, we still have the flexibility to achieve this:

  1. 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 this will do the job – possibly on a site wide settings page)
  2. We need a method of working out how close we are to a match being made – in this case how many seconds are left. This data needs to be delivered to the browser.
  3. We need some client side script that will continue the countdown and trigger the popup when the countdown reaches zero.

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 – 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 – which is then used with the user’s session start variable to calculate how long remains.


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 => 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]);
        }

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

            double timeToMatch = (matchTime - DateTime.Now).TotalSeconds;
            return timeToMatch < 0
                ? 0
                : timeToMatch;
        }
    }
}

The final part is to use this in a page:


   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("4c3bb8b2-4e8e-4fbc-bc24-5018e8c935af");

      //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();
   }

and then write some javascript to handle this (also perhaps write it slightly better than below. Hey I’m no javascript developer – yet!)


  <script type="text/javascript">

        function setAlertTimeOut() {
          var timeToLive = '<asp:Literal id="TimeToLive" runat="server" />';
          if (timeToLive > 0) {
              setTimeout('AlertMe()', timeToLive);
          }
        }

        function AlertMe() {
            alert("Time is Up");
        }

    </script>

and also don’t forget to call the method setAlertTimeOut() when the browser loads your page. I’d also imagine that your front end will need to do something a little more fancy than pop up an alert……….

Written by mark

April 17th, 2012 at 10:00 am

Posted in C#,Code,EPiServer

A Page Type security overview plugin for EPiServer

with 2 comments

I’ve been dealing with more of EPiServer’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  security policy (through an admin panel for example) but also having a current and clear overview of your security setup.

Whilst EPiServer provides this for the creating page functionality (Set Access Rights page and the page-tree), it doesn’t offer this for Page Types. Certainly this is something we can improve upon so I’ve put together a simple Admin Plugin (built using MVC – why would you use anything else these days?)

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.

A Nuget package (FortuneCookie.PageTypeSecurityOverview) built against EPiServer 6R2 is available from the EPiServer Nuget feed. The source code is available on GitHub – https://github.com/markeverard/FortuneCookie.PageTypeSecurityOverview

Page Type Security Overview

Written by mark

April 12th, 2012 at 2:00 pm

Posted in EPiServer

FortuneCookie.PropertySecurity version 2.0

without comments

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:

  1. It’s now absolutely dependent on PTB2 – you’ll see why below.
  2. PropertySecurity attributes can now be applied to PropertyGroups – this is why we need PTB2. You can now add a class level definition to a PropertyGroup definition
  3. PropertySecurity Attributes can now be applied to Tab class definitions – providing a shortcut to more granular management of property security.
  4. The ApplyToDefaultProperties functionality has been removed – this created some problems with the required validation settings – meaning it was possible to publish phantom pages with incomplete information.

The following hierarchical rules apply to attributes:

  • A property level [Authorize] attribute in a PropertyGroup will override any other setting
  • A property level [Authorize] attribute not on a PropertyGroup in a TypedPageData class  will tabs or class level settings
  • An [Authorize] attribute on a tab will be honoured next and take preference over a class level setting
  • A class level [Authorize] attribute on a tab will take preference only if the above aren’t matched

An updated Nuget package (FortuneCookie.PropertySecurity) built against .Net 4.0 / EPiServer 6R2 and PTB 2.0 is available EPiServer Nuget feed. The source code is available on GitHub – https://github.com/markeverard/FortuneCookie.PropertySecurity

Written by mark

April 10th, 2012 at 12:00 pm

Posted in C#,EPiServer