Wednesday, 25 March 2015

Chrome doesn't always expire session cookies and what it means for Sitecore DMS

So I was working through an issue with a customer recently and we couldn't work out why a certain behavior was happening and why it appeared to be happening on some browsers and not others. After a bit of digging we discovered that it was to do with the way Chrome manages session cookies.  After solving the specific issue the conversation turned to what does this mean for DMS tracking, particularly with the uptake of chrome in the market.

To put it in context Chrome is becoming pretty popular on the web according to http://gs.statcounter.com/ it is currently sitting at about 49% globally. So any change in the behavior of Chrome can dramatically change the way we need to build solutions.

A session cookie, according to webopedia.com, is: "a cookie that is erased when the user closes the Web browser. The session cookie is stored in temporary memory and is not retained after the browser is closed." This means that traditionally we have been able to set these cookies and assume that they will have expired after the user has closed their browser and won't be present when they come back to the site.

The change that Chrome introduced is it introduced a "Continue where you left off" piece of functionality. When this mode is enabled it aims to provide users the ability to exactly restore their browser to the state it was when they closed it. This includes reinstating any session cookies they had set during their last session. The other point of interest is that this appears to be the default setting on Chrome for mobile.

Now I'm not going to get into the debate of whether its a feature or a bug, or what the security aspects of it are, I'm only interested in how we account for this in the solutions we build.

To put this in context I will use the Sitecore DMS session tracking cookie as an example. Note that I haven't confirmed what versions of Chrome or Sitecore are affected by this, so if you run into this issue please contact Sitecore support. I do know that the issue doesn't exist with Sitecore 7.5 and up as the xDb does not use the same cookie structures as the DMS. Also note that between my writing of this post and when you might be reading it, it is likely that an official patch has been released by Sitecore, so please check release notes or contact Sitecore support.

The Sitecore DMS uses a cookie dropped on a users machine to identify requests that come from a specific session. The information gathered based on the cookie relates to value per visit, page view tracking, time on site, etc. Essentially it is a pretty important piece of information and demonstrates how a seemingly small change in the browser landscape can have unforeseen consequences on web applications.

The way of preventing this from occurring with your cookies is to essentially stop using session cookies and to use a sliding timeout for your cookies instead. The example below is a Sitecore related patch, but the logic can be applied in non-Sitecore related implementations.

In the DMS the visit cookie is set in a place that's not easy to get a hook for, so the easiest way of setting the desired expiry time on the cookie is to update the cookie once the DMS has set it. I have chosen to set this at the end of the "renderLayout" pipeline, which ensures that the DMS has set its values already and won't override anything. It also means that the code will be invoked on every request, which provides the effect of setting a sliding window. The code is as follows:

public class ForceScVisitCookieExpiration
{
    public void Process(PipelineArgs args)
    {
        var context = HttpContext.Current;
        var sessionCookie = context.Request.Cookies.Get("SC_ANALYTICS_SESSION_COOKIE");
        if (sessionCookie != null)
        {
            var timeout = Sitecore.Configuration.Settings.GetIntSetting( "SitecoreVisitExpirationTimeInMinutes", 60);

            sessionCookie.Expires = DateTime.Now.AddMinutes(timeout); 
            context.Response.SetCookie(sessionCookie);
        }
    }
}

All that the code does is retrieve the existing value for the cookie from the request (only needed if you don't have access to where the cookie is being set) and then sets an expiration time for the cookie. This means that the cookie will expire at the designated time, meaning that if a user closes their browser for that period of time, when they come back the cookie will be gone.

The upshot of all of this is that people need to be aware of this behavior in Chrome and that they need to update their solutions to cater for it, whether we like it or not.

Tuesday, 17 February 2015

The rich page/experience editor

As we move down the path of personalisation in Sitecore we are finding that our editors are spending more and more time in the "Page/Experience Editor" and less time in the "Content Editor". This means that editors are starting to expect to be able to do all of their editing in the "Experience Editor", and why shouldn't they? We are rendering the page in edit mode, we have full control, lets use it.

Below is a simple example of what can be done using a carousel as an example. Now put aside your concerns about carousels (http://shouldiuseacarousel.com/), this is designed as a thought provoking exercise aimed at getting you to think about how you can make life better for you content editors within your own project domain, not as a way of building a carousel.

The reason that a carousel is useful as a thought provoker is that it has some characteristics that don't make it feel like an easy fit for the experience editor. These include
  • Unknown number of slides
  • The order of content in a carousel is important - the first slide gets more views then the last
So without further adieu lets show you what the experience editor experience could be like


Notice the new buttons? This style of functionality has typically been implemented using edit frames and there is a lot of content there around it (e.g. http://www.cmsbestpractices.com/how-to-properly-use-sitecore-edit-frames/), but  we can also include these buttons directly into your site and and simplify the editing experience.

Now what have I actually done to get this running, well there are two main things, the first being accept that you are going to need to do different things in edit mode to delivery mode. This is as simple as adding an if(or multiple ifs) to your view layer to check what the current page mode is.


The next step is to understand what commands are available to you and how you can additional commands. As mentioned before, traditionally these commands would be implemented using the edit frames functionality and the commands that I am using are exactly the same. 

If you were to configure an edit frame or sub layout with a series of commands and inspect it you would see something like the following.


Essentially each edit frame button/command is a JavaScript click event with a command, webedit:new, and an item id associated with it. Knowing that Sitecore uses this approach to triggering commands we can build our own renderings taking this into account. So going back to the buttons in my carousel, each button essentially has the same JavaScript rendered from an MVC helper as demonstrated below.

namespace Website.Helpers
{
    using System.Web;
    using Sitecore.Data.Items;

    public class PageEditorHelpers
    {
        public HtmlString NewItemButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:new(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString DeleteItemButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:delete(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString MoveItemUpButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('item:moveup(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }        
        
        public HtmlString MoveItemDownButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('item:movedown(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }

        public HtmlString SortItemsButton(Item parentItem, string buttonText)
        {
            return new HtmlString(string.Format(@"<a href=""#"" class=""button"" onclick=""javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:sortcontent(id={1})')"">{0}</a>", buttonText, parentItem.ID));
        }
    }
}

Once we have the helper setup it's easy to include them in the markup and customise the experience for our editors.

Now keep in mind that this was a thought provoking exercise and you can create any custom command you like, or add any code you like. What can you do for your editors? The ideas become endless and all of those custom UI's you build for you public users can now also be used to enhance the experience for you editors.

What happens when you cast an IQueryable to an IEnumerable

Recently I was digging through some code and came across an issue where the "Where" expressions I was applying in code were not being run against the database. After a bit of digging it turned out to be related to an implicit cast of an IQueryable<T> to and IEnumerable<T>. This cast affects the query generation process with every clause added after the cast being run in memory.

So how about an example to demonstrate it and make it clearer. Looking at the two unit tests below, what would you expect the resulting SQL query to be? Keep in mind the IQueryable inherits from IEnumerable, so the casting is valid.

    public class UnitTest1
    {
        [TestMethod]
        public void RunQueryAsIQueryable()
        {
            IQueryable<Record> records = new ModelContext().Records;
            var result = records.Take(10).ToArray();
        }

        [TestMethod]
        public void RunQueryAsIEnumerable()
        {
            IQueryable<Record> records = new ModelContext().Records;
            var result = ((IEnumerable<Record>)records).Take(10).ToArray();
        }
    }

Here are the results from SQL profiler

As IQueryable
    SELECT TOP (10) 
    [c].[Id] AS [Id], 
    [c].[Name] AS [Name]
    FROM [dbo].[Records] AS [c]

As IEnumerable
    SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[Records] AS [Extent1]

As you can see the IQueryable "Take/Top" clause is run against the database, where as the IEnumerable "Take" clause is not. Now consider the following example.

    public class UnitTest1
    {
        [TestMethod]
        public void RunHybridQuery()
        {
            IQueryable<Record> records = new ModelContext().Records;
            var result = ((IEnumerable<Record>)records.Where(record => record.Name.StartsWith("something"))).Take(10).ToArray();
        }   
    }

    SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name]
    FROM [dbo].[Records] AS [Extent1]
    WHERE [Extent1].[Name] LIKE N'something%'

As you can see with this example everything up until the cast(note the top 10 is missing) runs against the database.

This "unexpected" behavior is actually by design and relates to the reason why we have the two interfaces, as opposed to just IEnumerable. An IEnumerable is something that is enumerated, i.e. looped over. An IQueryable on the other hand represents something that can be queried, generally by a query language.

Seems pretty self explanatory, the confusion that comes in is when we use the LINQ syntax to mix these two concepts into a single statement. Because of the fluent nature of the LINQ API it can often be hard to know exactly what the parameter and return types of each method in your chain are and what the actual query being run is(without profiling). So the lesson here, be careful and don't rely on LINQ to do all of your work for you, it is only as smart as the person who wrote it.

Tuesday, 6 January 2015

Creating a Clicks report for Sitecore Email Experience manager (ECM)

Recently I was out on site with a client working through an ECM implementation and some questions came up around the reports that are provided out of the box. The reports that are provided out of the box are all looking at the value of a user interaction with an email, as opposed to whether they clicked a link in an email or not. While this provide you a much more rounded picture of how a user interact with an email and what value you can associate with a particular send a lot of people are still expecting the traditional "Click" report that you get from other email platforms.

So, I decided to build one.

The first thing to note is the ECM has been built to be extended and that it already collects all of the information to produce a click report. I recommend looking at the following to see how you can customise ECM:

Now that you have the background on where to customise ECM and where it stores its data, its just a matter of pulling the pieces together to build your own report.


I have open sourced an implementation on my git repository over at https://bitbucket.org/ctekempel/ecmreports and hope to add some more detail about the implementation when I get some time, but thought I would put it up now just in case I don't. Once you pull down the git repo you will need to:

  • Compile and copy across the appropriate files
  • Deserialize all of the items in the "items" folder
  • Add a report to each of the task types report pages in the ECM:
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/AdHockTaskPage/Reports
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/PeriodicalTaskPage/Reports
    • /sitecore/system/Modules/SPEAK/EmailCampaign/TaskPages/TrickleTaskPage/Reports

  • To add the report you need to add a “/sitecore/layout/Renderings/Email Campaign/Speak/ObjectDetailListObserver” control to the page and then set its datasource to “/sitecore/system/Modules/SPEAK/EmailCampaign/Controls/List views/Custom ECM Reports/Clicks”

If you have any questions before I get this post fully updated, drop a note in the comments and I will get back to it ASAP.

Also if anyone has ideas for other reports, or wants to contribute to it, please reach out.

Thursday, 2 October 2014

Sitecore Trendspot ANZ 2014

This week I had the opportunity to attend both the Sitecore Partner Summit and Trendspot down here in Sydney. Off the back of attending I thought I would share my top three take outs from the two events.

3. The Experience Database is the Future of Sitecore
More then anything else, the experience database is the key to success to Sitecore in the future and Sitecore is investing heavily in this area going forward.

If you haven't heard about it, it has been built as an efficient big data store for all of you data about people. I know that sounds like it is starting to take on the role of a CRM and it does feel like that when they present what it can do, but Sitecore has repeatedly said that it is not a CRM replacement, but it can certainly pull and push data into a CRM system.


The xDB, as its referred to, is tightly integrated into all parts of Sitecore, as you would expect, but has also opened up the ability to integrate data from a tonne of other sources. This is the major difference to the DMS that we have today.

2. The Device Ecosystem is Alive
At the moment I am feeling all inspired by the use of non-traditional digital channels by the partners and Sitecore themselves at the conference. 

There has been a lot of buzz for a while now around digital breaking out of the browser and the phone and starting to integrate with things like i-beacons, digital signage, second screen, etc. But to be honest it has all felt out of reach of the average project. This conference has shown that the technology has matured and it is now much easier to integrate these tools into you marketing plan, as well as into Sitecore. 

It has also shown what can be done when you start integrating all these things into Sitecore, leveraging some of the cool kit they have developed. With the new scale that's available  imagine the forms of communication you can have with your consumers if you connect  to one person via
  • in-store wi-fi 
  • iBeacons
  • web
  • print
  • TV/streaming
  • paid advertising
On top of that imagine if you can do it real time. This is what Sitecore is promising us and what some of the demonstrations have shown us.


1. Sitecore is not a CMS
The biggest take out for me from the conferences is that Sitecore is no longer just a CMS. With the work Sitecore is doing around experience marketing it is dramatically exceeding the boundaries of what we consider a CMS. I can see scenarios in the future where:

  • Sitecore is used to personalise and track sites that are built on other CMS's. Think legacy sites
  • Sitecore is used for email distribution
  • Sitecore is used as a pure marketing tool for tracking campaign success and consumer engagement across all platforms
Obviously all of these scenario's can be augmented by the CMS component of Sitecore, but in the future I see the CMS component of Sitecore be exactly that, a component in a bigger ecosystem of functionality that the platform provides.

Summary
The thing that surprised me most about what I have taken out of this conference, keeping in mind I'm a tech guy not a marketing guy, is that my take away's have all been around what can we do for people. There was certainly a lot of good tech presentations there, but I already have confidence in the platform from a tech point of view. The way the technology is evolving is allowing us to chase down those interesting cross platform project, which to be honest is quite exciting.

Monday, 7 July 2014

Leaving Global.asax in Sitecore Untouched

So one of the things I strive to do on each project I work on is to leave core systems completely untouched(where possible). There are two main reasons that I do this:
  1. The upgrade path. If you haven't modified the system you want to upgrade and you have no concrete dependencies on its files, then in theory you can upgrade it quite easily, by replacing it.
  2. Multi-tenant architectures. If you are working in a multi-tenant scenario, then avoiding modifying shared resources can make you life a lot easier, as individual applications are self contained.
With a lot of my work involving Sitecore, I come across these two scenarios quite regularly and up until recently I had strategies for managing:
  • Views/Layouts - separation by folder convention
  • Sitecore Items - separation by content tree convention
  • Sitecore configuration - separation by Sitecore config patching
  • .Net configuration - separation by asp .net configuration sections
But even with all of this I didn't have a great way of managing the separation of application start-up and shutdown events, that are typically setup in your global.asax file. Enter Web Activator (available on nuget here). To summarize the module simply it is a "A package that allows other packages to execute some startup code in web apps" (direct from the nuget site).

Now for an example, lets say we are using dependency injection and we want to setup our dependency configuration and then tear it down on application start-up/tear down and we don't want to alter and of the out of the box Sitecore files. The code looks something like:

   
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(UnityWebActivator), "Start")] 
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(UnityWebActivator), "Shutdown")]

namespace Sample
{
    using System.Linq;
    using System.Web.Mvc;

    using Microsoft.Practices.Unity.Mvc;

    /// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
    public static class UnityWebActivator
    {
        #region Public Methods and Operators

        /// <summary>Disposes the Unity container when the application is shut down.</summary>
        public static void Shutdown()
        { }

        /// <summary>Integrates Unity when the application starts.</summary>
        public static void Start()
        { }

        #endregion
    }
}

The important bits of this are:

  • WebActivatorEx.PreApplicationStartMethod - this invokes the specified type/static method combination for the global application start event.
  • WebActivatorEx.ApplicationShutdownMethod - this invokes the specified type/static method combination during application shutdown.
Now, armed with this, there is one less file you need to modify from a base Sitecore install.

Monday, 2 December 2013

Sitecore Parameters Template Field

As we move into using the DMS more and more often we are also starting to use the page editor more and more often. This leads to a need for making the way we insert sub-layouts/renderings easier for our users and it turns out Sitecore has made a start on this already by giving us small features that can make a big difference, in this case the "Parameters Template" field.

When you add a presentation component to a page in Sitecore you have the option of editing its component properties and this it what it looks like by default:



And if you wanted to customise the data being passed to this instance of the sub-layout(beyond the data source) you would need to add additional properties as key value pairs to the "Parameters" section. In my mind this is fraught with danger, it is free text and there is no guarantees around the names or types of values being passed to your control.
This is where the "Parameters Template" field comes into play. If you take a look at any of your sub-layout or renderings items you will notice there is a field called "Parameters Template"
By setting this field you are giving Sitecore a prompt on how to ask for the values when editing the "Component Properties" and allows you to name and type the values. 

All you need to do is create a template that inherits from the "Standard Rendering Parameters" template: create the fields you want and set the "Parameters Template" field to point to it.


And "Hey Presto!!", when you edit the component properties of the sub-layout you get the fields, named and typed. Therefore removing the possibility of typos and making the editing process that much nicer.


Now I should probably mention that this doesn't change anything form a code point of view in as much as these values all still come in via the parameters collection that you have without this field, its just making the editing process nicer.

How to disable "Add Users" in Sitecore's Platform DXP

 I have seen a few posts going around the community asking how to disable the "Add Users" button in Sitecore Platform DXP.   This ...