Wednesday, April 11, 2018

SIFLess for easy Sitecore 9 installation

Lazy me, here's a link to an article: -

h/t to RockPaperSitecore for this. Works well, by the way :)

Wednesday, February 1, 2017


Thursday, January 12, 2017

CodeDen's - Sitecore Habitat Transformer

What is Sitecore Habitat ? 

It's an example implementation of the Helix design principles and conventions for a Sitecore project.

Dennis Lee has thoughtfully provided a nice and safe means of accelerating the process of re-implementing Habitat (the demo) in your own project.

Get it here

Thursday, October 6, 2016


This is the TLA for a new venture which I, as senior Website-Building Fromage to the Gentry, have been asked to make.

My brief was to make it a) simple to edit and b) editable by simples, so I decided to re-visit my own CMS with a view to "getting this done" (TM). (PS Sorry Sitecore, but you're not going to stoop to this end of the market or their budgetary constraints !)

So as I've basically copy-paste inherited my CMS into hmmm 5 or 6 websites now, with the usual "it deviates here" shenanigans that you get when copying and pasting an entire Visual Studio solution and databases for re-use.

I've done some more sensible stuff, including modularisificating my CMS framework into, let's see now, actual modules (the CMS and its base stuff is now in its own assembly, yay !)

I've studied Bootstrap and the whole "semantic HTML" concept quite a lot at PING Works, mainly as a side-effect of being asked to POC Sitecore Habitat. I'm also trying to do this in my own CMS; with the objective being to understand semantic HTML, modularity and re-skinnability as central tenets to both Sitecore builds (i.e. high-end clients) and my own (i.e. not so).

What in the hell am I talking about ? Dunno mang, watch this space as I reveal all ! Or just a bit. Or maybe nothing. More to follow. Maybe.

Friday, May 6, 2016

Theatre on the River - reskin


My sister runs a very successful drama teaching company in London, and her current site is nice but it uses device detection ( if you're interested) for mobile/tablet which is no longer the cool way to handle mobile traffic (as now enforced by our Google overlords).

Instead, sites must be responsive which is hardly a term new to anyone reading this drivel but for those of you who've been living in a cave eating beetle dung for the last few years, "responsive" is an HTML 5-based concept where the site's presentation layer (the HTML and CSS) must adapt to the device the site is rendering into.

This means no cop-out of sniffing the device server-side and redirecting to a /mobile set of layouts/masterpages/etc but instead - there is just one site to rule them all. Which is done using CSS media queries.

This isn't the first responsive site I've worked on, ohnono. My brother runs a very successful glass machinery oligarchy in Rugby (home of the game, Rugby fans!) and his site was the first independent site I rebuilt in a responsive style.

Glass Machinery Solutions Ltd

As you can see, it looks good on

a) desktop,
b) tablet, and of course
c) mobile

All served from just the one URL and this pleases our Google overlords, who will continue to rank your site in accordance with their holy scriptures. And not penalise you for redirecting to effectively another site (or worse, your site is not mobile-friendly at all and therefore you fail at everything).

I'm no front-end guru; never have been, don't want to be either. It'll push other, more useful stuff out of my head such as being able to order a beer, or pulling a wheelie between lanes of traffic. What I am good at doing with front-end stuff is glueing someone else's efforts together into an ASP.NET application.

I do understand media queries, they're not hard. I do not however have the necessary skill/patience to make sure the resulting CSS & HTML functions across all browsers, devices and small hairy marsupials.

So ! HTML5Up to the rescue. These guys offer a bunch of free, responsive skins (a bunch of CSS, JavaScript and sample HTML pages) for you to use, as long as you acknowledge their awesome efforts (no probs there guys!).

They also have even more elaborate skins you have to pay for, not a lot, but whether you choose to go the free or paid route, I can highly recommend their work.

The new site needs some image work and polishing (so don't mail me about images being different heights or whatever COS YEAH I KNOW) but I'm sure you'll agree, it looks better. For minimal outlay.

People dedicating their lives to making awesome HTML 5 skins - you have my utmost respect and infinite gratitude.

BTW please don't spam my sister's email using the Contact Us form.

BTTW I'll know who did it and I will find you

BTTTW Look at me. I'm the captain now.


Thursday, June 4, 2015

Be careful what you delete for II - Judgment Day

A while back I posted this regarding deleting data from Sitecore's Analytics database.

TL;DR - Sitecore 6.4 (and possibly other versions using SQL-based analytics) do not want you to truncate the IPOwner table. Analytics stops working.

Lo and behold, we discover today that one of our Sitecore applications hasn't been collecting analytics for a while. Investigation of the database revealed - gasp - no data in the IPOwner table !!!

The Sitecore logs revealed a multitude of Foreign Key constraint violations; specifically the foreign key IP.IPOwnerID - IPOwner.IPOwnerID. It's trying to add a row to the IP table using an IPOwnerID that does not exist.

Wait, what ? There aren't any rows in IPOwner ?

Suspecting magic GUID foul play and thinking that Sitecore is perhaps expecting a row to be there, we crack open a fresh copy of Sitecore 6.4's OMS database and sure enough, hiding in there was this little fella: -

IpOwnerID Name Country VisitorIdentification ExternalUser
9F28FB1A-BDDA-4CE6-9521-D7E6C6D8BB9D (Pending) (Pending) 0

And it all makes sense. While waiting for MaxMind GeoIP service to return something, Sitecore is using this guy as the IPOwner for a new session until the queued service lookup completes (hopefully), so it can write some meaningful location data to the IP record.

Added this row.. tested the site.. analytics starts recording stuff !

So now we know. Delete all the IPOwner rows if you want, just make sure this row finds its way back in.

Tuesday, March 19, 2013

SQL Row_Number() OVER and how to cure indeterminate sort order

There's been plenty of wibbling on Stack Overflow about how paging and sorting at SQL Server level using the Row_Number() function can produce records ordered unpredictably between repeated executions of the same query; perhaps you wouldn't normally do this, perhaps you would and as required by my scenario, I did.

And saw it myself - the variations weren't great but they were there and that's annoying.

I checked and double-checked my stored procedure - it was doing what it was supposed to.

Came across this via Stack Overflow - - and I'll repeat the most pertinent part here: -

There is no guarantee that the rows returned by a query using ROW_NUMBER() will be ordered exactly the same with each execution unless the following conditions are true: -

  • Values of the partitioned column are unique.
  • Values of the ORDER BY columns are unique.
  • Combinations of values of the partition column and ORDER BY columns are unique.

How to fix this ?

So - Microsoft themselves admit this is a problem. There is of course a solution, and mine was a table variable.

  InvoiceID INT,
  RowNumber BIGINT,
  TotalRowCount BIGINT

Because the actual results my query returns contained a number of identical field values in many cases (same Customer Name, same Status.. etc) the three rules outlined in the MSDN article weren't being met; hence the problem. You can guarantee the order by stripping the columns returned from the actual query back to a bare minimum - a key field (InvoiceID in my example), the RowNumber itself and (optionally) the result of the partition column expression.

Having defined our table, I then run the complete query but returning only those 3 fields needed: -

INSERT INTO @IDTable (InvoiceID, RowNumber, TotalRowCount)
  Row_Number() OVER
    WHEN @SortExpression = 'DateCreated'  
     THEN  i.DateCreated

    -- snip - long list of fields to order by

  ) AS RowNum,
  COUNT(*) OVER(PARTITION BY 1) as TotalRowCount 

  FROM ..
  WHERE ..

 ) results

 WHERE RowNum 
                BETWEEN (@PageIndex * @PageSize + 1) 
                AND     ((@PageIndex * @PageSize) + @PageSize)

That deals with correct ordering of results; now run another query to join back to @IDTable, this time also retrieving all the coulmns needed: -

 SELECT i.InvoiceID, c.CustomerName, .. etc
 FROM @IDTable idt
  INNER JOIN Invoice i WITH (NOLOCK) ON idt.InvoiceID = i.InvoiceID
  INNER JOIN Customer c ..

    -- and so on 

Ok so there's some overhead involved with running two queries as opposed to one; but the execution time is still fast and it gives me exactly what I want. You should have seen what was happening before..