Wednesday, 16 August 2017

Sitecore Tracking Field Parsing - the Native Way

When we assign profile cards, goals or attributes (outcomes, events, etc) to a page content item, Sitecore stores the information in the Tracking (actual name __tracking) field under the Advanced section, as XML which looks like below (I am using the Sitecore Helix Utilities demo site for example):


Now if we switch to the raw value, we will see it is stored in XML, which I have formatted it for ease of viewing:
  
<tracking>
   <profile id="{D016ADEF-7737-4289-A85F-FE0055F49C8E}" name="Utilities Persona" presets="evan the eco-owner|100||">
      <key name="Sign-up for service" value="1" />
      <key name="Solar_Enviro Programs" value="5" />
      <key name="Budget_Savings Offers" value="4" />
      <key name="H of H_Community" value="3" />
   </profile>
</tracking>

There might be some cases where you want to parse this and get the information out of it and I have seen many developers parsing it by loading the value into XmlDocument and then read its nodes. This works fine however we would imagine Sitecore should have already had something doing this?

Answer is yes of course :) So, we can use the following code to get a strongly-typed object that represents this information.

// using Sitecore.Analytics.Data;

var pageItem = Sitecore.Context.Item;
var trackingField = new TrackingField(pageItem.Fields["__Tracking"]);

// Loop through all profiles (if multiple profile cards are assigned)
foreach (var profile in trackingField.Profiles)
{
    // Loop through all profile keys for current profile.
    // Here we want only the ones that has value greater than 0, for example.
    foreach (var k in profile.Keys.Where(o=> o.Value > 0))
    {
        // Do something
    }
}

The above example shows how to read profiles. If you have stuff like campaigns, goals, events that you need, in the TrackingField class there are collections for them as well:


Note that goals are same as events so you will find it under the Events IEnumerable.

Hope this helps!

Friday, 30 June 2017

Find MongoDB contact and interactions using SC_ANALYTICS_GLOBAL_COOKIE

These days I was working on resolving some issues with Sitecore Analytics and need to find the corresponding contact stored in the Contacts collection database in MongoDB easily.

[Update] 15 Aug 2017: added query output for finding all interactions with provided contact ID.

Sitecore generates the analytics cookie value (in GUID) and stores it in the SC_ANALYTICS_GLOBAL_COOKIE cookie which looks like 95f08e09d56348c9bc285080e91be04b|False. That letters/digits combination is a short, lowered version of GUID which is an important identifier for the contact record that gets stored in MongoDB.

However when you try to find this in MongoDB (using Robomongo which is now Robo 3T, make sure to check the latest version), you will not find it because some parts of the GUID are shifted (i.e. first 8 characters, followed by next two groups of 4 letters).

To make things easier, you could run a C# Program query in LINQPad by pasting the below code in, or visit my fiddle page.

    
    void Main()
    {
       // Value from SC_ANALYTICS_GLOBAL_COOKIE (you can copy the |True or |False part which will be trimed too)
       var guidFromCookie = "95f08e09d56348c9bc285080e91be04b|False".Split(new char[] {'|'})[0]; 
       var mongoDbLUUID = string.Format("{0}-{1}-{2}-{3}-{4}",
                              Flip(guidFromCookie.Substring(0,8)), 
                              Flip(guidFromCookie.Substring(8,4)), 
                              Flip(guidFromCookie.Substring(12,4)),
                              guidFromCookie.Substring(16, 4),
                              guidFromCookie.Substring(20,12));
  
       Console.WriteLine("MongoDB query:");
       Console.WriteLine("db.Contacts.find({" + string.Format("_id:LUUID('{0}')", mongoDbLUUID) + "})");
       Console.WriteLine("All interactions with this contact:");
       Console.WriteLine("db.Interactions.find({" + string.Format("ContactId:LUUID('{0}')", mongoDbLUUID) + "})");
    }

    string Flip(string s)
    {
       var output = "";
       for (var i=s.Length-2; i>=0; i-=2)
       {
           output += s.Substring(i, 2);
       }
 
       return output;
    }

The code will output a query which you can paste directly to Robo 3T.

Thursday, 11 May 2017

CSS rule that could break your Sitecore 8.2 Experience Editor

Today when I was using the Experience Editor on my Sitecore 8.2 Update 3 site and I found that nothing of the following works:

  • Assigning renderings to placeholders
  • Some of the buttons in the ribbon does nothing when clicked
  • Etc, etc
I have checked Chrome console logs... no javascript errors, no 500 or 404 under network tab. Checked Sitecore logs... no exceptions were thrown.

What could it be? I have started scratching my head...

Checking here, checking there, asking my colleague and starting removing whatever is on the page one by one.

At the end we figured out that there is one CSS rule:

body > iframe { display: none;}

We removed it and the Experience Editor starts working again. Why?

This rule effectively hide any iframes that are directly under the body tag, whether they are created dynamically by external javascripts or by yourself. Unfortunately Sitecore Experience Editor also has an iframe directly under body for serving the modal dialog. Therefore when this rule is present, the functionality behind the buttons (that pop up a modal dialog) actually works but the dialog is not showing.

We have only tested this on Sitecore 8.2 so not sure if it affects earlier 8.x versions. The iframe used by Sitecore looks like:

  
  <iframe allowtransparency="true" 
         frameborder="0" 
         id="jqueryModalDialogsFrame" 
         src="/sitecore/shell/Controls/JqueryModalDialogs.html">
      ...
  </iframe>

So once we know this, we can get around this by excluding this from the CSS rule:

body > iframe:not(#jqueryModalDialogsFrame) { display: none;}
Hopefully this helps!

Monday, 1 May 2017

Sitecore Habitat and Fortis

If you don't know what is Habitat yet, please have a look at its Github: https://github.com/Sitecore/Habitat.

By default, Habitat does not use any mapping tool (such as Glass Mapper, Fortis, or the emerging Synthesis) so keep it simple however it does not mean that Sitecore doesn't prefer using one of those.

I have created a fork of the original Habitat solution and made it Fortis-enabled. A Fortis.Foundation module is added to the foundation layer which is responsible for the registration of Fortis and the code-generation of the Fortis model based on Unicorn.

You can find the repo here: https://github.com/codingdennis/Habitat/tree/feature/fortis-integration.

[Updated 2017-05-03] I have also updated this Habitat to support Sitecore 8.2 Update 3, check https://github.com/codingdennis/Habitat/tree/feature/fortis-integration-sc82u3 if required.

Happy Habitating!

Wednesday, 29 March 2017

Sitecore SIM 1.5

There were heaps of development work undergoing since the last release 1.4 Update-3 about a year ago. Alen is in the process of merging of everything from develop to master and we should expect version 1.5 to be released soon which I was lucky enough to also contribute a small portion to it, which allows prefixing the SQL database names so multiple databases could be created for different instances.

Keep an eye on the SIM's GitHub for any updates. You can also find it in Sitecore Marketplace.

Thursday, 23 February 2017

Script to flush Sitecore xDB

Many people have been talking about how to flush current visit to xDB without playing around the session timeout. Here is just a script ready for use when I need it.

<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Flush xDB</title>
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Sitecore.Analytics.Tracker.Current != null)
            {
                Sitecore.Analytics.Tracker.Current.EndTracking();
                Session.Abandon();

                Response.Write("xDB flushed.");
            }
        }
    </script>
</head>
<body></body>
</html>

Save as a ASPX page and put it somewhere on the site and browse to it to flush current visit into xDB.

Wednesday, 22 February 2017

Sitecore ShowConfig on CD servers

I have to say that this is not recommended, not recommended, not recommended... and you are doing this on your own risk.

So, what is it? We have followed all the recommendation on disabling stuff on CD servers but I am sure sometimes we want to see the famous showconfig results on CD servers so we can investigate the configurations only for CD servers. Because CD should not have Sitecore client and the admin pages, so we have removed them. Then how?

Sounds evil? Yes it is so risk is yours :)

When Sitecore does this in CM server, the showconfig.aspx checks if you are logged in. We cannot do that on CD so we just need to create the same page with code that does not do the security checking and put this, say, EvilShowConfig.aspx somewhere on CD server and remove it as soon as you have collected the configurations.

Save the following content into a text file named EvilShowConfig.aspx and put the file on CD at the location of your choice and browser to it.

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import NameSpace="Sitecore.Configuration" %>
<%@ Import NameSpace="System.Xml" %>
<html>
    <head>
        <title>Very Evil ShowConfig</title>
        <script runat="server">
            protected void Page_Load(object sender, EventArgs e)
            {
                XmlDocument configuration = Factory.GetConfiguration();
                Response.Clear();
                Response.ContentType = "text/xml";
                Response.Write(configuration.OuterXml);
                Response.End();
            }
        </script>
    </head>
    <body></body>
</html>