Experiments In Code
Sitecore, .Net and the web
Sitecore, .Net and the web
Sep 1st
Posts in this series:
So this is the second post on how to unit test Sitecore, in this post I look at how to restructure some simple code so that we can test the code via the NUnit GUI.
For this example we will have a very simple sub-layout that contains a comment form, this form takes a comment, username and email address from the user and then adds this to the Sitecore database. So the code for out sub-layout looks like this:
public partial class AddComment : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
submit.Click += new EventHandler(submit_Click);
base.OnInit(e);
}
void submit_Click(object sender, EventArgs e)
{
//a few presets for a comment
Guid commentTemplate = new Guid("{73888B25-314C-4F93-8F7C-48E916C054C9}");
DateTime commentDate = DateTime.Now;
string commentName = string.Format("comment-{0}", commentDate.ToString("dd-MM-yyyy-hh-mm-ss"));
//create a new comment
Item parent = Sitecore.Context.Database.GetItem("/sitecore/content/home/news/interestingarticle");
Item newComment = parent.Add(commentName, new TemplateID(new ID(commentTemplate)));
//populate the comment
newComment.Editing.BeginEdit();
newComment["username"] = username.Text;
newComment["comment"] = comment.Text;
newComment["email"] = comment.Text;
newComment["date"] = DateUtil.ToIsoDate(commentDate);
newComment.Editing.EndEdit();
}
}
Aug 30th
Posts in this series:
I am currently working on a project that requires a lot of complex interaction with Sitecore, to be sure that it worked and so that future changes didn’t break what I had written I wanted to unit test the Sitecore interaction. However this has always been quite tricky in Sitecore. Due to Sitecores tight coupling to the database and the configuration files I had avoid trying to get this to work, actually it turned out to be quite straight forward.
As I was try to get this to work with NUnit I received a tweet about unit testing Sitecore by Alistair Deneys which performed the unit tests inside a web page on the site. I didn’t want to follow this solution because I already had unit tests that were being performed in the NUnit GUI. However Alistair’s solution does fill in some of the gaps left by this solution, you can see some of the advantages/disadvantages at the end of the post.
On to the important bit, the steps I took to get Sitecore working via NUnit, I will assume that you have a solution that has both a Website that contains the Sitecore solution and Class Library that contains your unit tests.
<configSections>
<section name="sitecore" type="Sitecore.Configuration.ConfigReader, Sitecore.Kernel" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, Sitecore.Logging" />
</configSections>


So we have now configured the Class Library for unit testing, next we need to be sure that everything works. For my test I wrote the following simple tests to ensure that everything was setup correctly:
[TestFixture]
public class SetupTestFixture
{
[Test]
public void DatabaseGet()
{
Database database = global::Sitecore.Configuration.Factory.GetDatabase("master");
Assert.IsNotNull(database);
}
[Test]
public void GetItem()
{
Database database = global::Sitecore.Configuration.Factory.GetDatabase("master");
Assert.IsNotNull(database);
Item item = database.GetItem("/sitecore/content");
Assert.IsNotNull(item);
Assert.AreEqual("content", item.Name);
}
}
I built and run the Class Library and launched NUnit, when the tests run the both pass:
For me this method has the following advantages:
These are some of the disadvantages/can’t do’s that I can think of at the moment.
I am sure there are more limitations and more advantages, as I continue to explore the limits of what can be performed via this method of unit testing, Â I will add it to the blog as I find out.
I will write another blog in a couple of days that address how to structure code so that it can be unit tested via this method and how we can get around the problem on not having a Sitecore.Context.
Aug 28th
I have migrated the Petrol Calculator I had written in my original blog to this one. Its quite interesting to see actually how much money it costs just to commute to work.
The tool itself is quite simple, it makes use of Google Maps API v3.1 to get the distance between two locations and then I use the sliders in jQuery UI for the MPG and price per litre.
I wrote this quite quickly so if you notice any problems please post a comment and let me know.
Aug 27th
This post has been migrated, original date 24 May 2010
I need a quick way to disable HTML caching on a Sitecore server. I didn’t want to mess around with the sites setting because I wanted something a little more generic.
You might be tempted to set Caching Enabled to false.
<!-- CACHING ENABLED
Determines if caching should be enabled at all
Specify 'true' to enable caching and 'false' to disable all caching
-->
<setting name="Caching.Enabled" value="true" />
However changing this to false will cause your site to never load! A better solution is to use the HTML Lifetime setting:
<!-- HTML LIFETIME
The lifetime of HTML fragments added to the cache.
Default value: 00:00:00 (ie. eternal life)
-->
<setting name="Caching.HtmlLifetime" value="00:00:00" />
Change this from 00:00:00 to 00:00:01.
Aug 27th
This post has been migrated, original date 17 Mar 2010
It seems that the Niceforms JavaScript does not raise the onchange event of the original checkbox when the checkbox image is clicked.
To correct this problem, and assuming you are using jQuery you need to find the inputCheck function in the NiceForms.js file. Then update the el.dummy.click function as follows:
el.dummy.onclick = function() {
if(!this.ref.checked) {
this.ref.checked = true;
$(this.ref).change(); //added
this.className = "NFCheck NFh";
}
else {
this.ref.checked = false;
$(this.ref).change(); //added
this.className = "NFCheck";
}
}
Aug 27th
This post as been migrated, original date 26 Feb 2010
Sitecore have release the Online Marketing Suit. One of the nice aspects of OMS is that ability to test different page content to see which content users respond best to, this is called Multivariate testing.
I quickly show how this is setup. Firstly we create a the different items that contain the content variations. So in the picture below you can see that I have three different home nodes.

When the user visits the site they are taken to /sitecore/content/home but they may see content from /sitecore/content/home2 and /sitecore/content/home3. This content is injected by the multivariate test.
Now I have my content the next step is to create the multivariate test. This is setup using the Marketing Centre application. For this example I have setup an incremental test strategy that simply picks the next multivariate test item to display to the user:
public class IncrementalMultiVariateTestStrategy : IMultiVariateTestStrategy
{
const string _cookieName ="aegeagaegaeWeafea2";
#region IMultiVariateTestStrategy Members
public Item GetTestVariableItem(Item item, Item multiVariateTest)
{
if (!multiVariateTest.HasChildren) return null;
int index = Cookie == -1? 0 : Cookie;
if (index >= multiVariateTest.Children.Count) index = 0;
Cookie = index + 1;
return multiVariateTest.Children[index];
}
#endregion
private int Cookie
{
get
{
int i = -1;
if(HttpContext.Current.Request.Cookies[_cookieName]!= null)
int.TryParse(HttpContext.Current.Request.Cookies[_cookieName].Value, out i);
return i;
}
set
{
HttpContext.Current.Response.Cookies.Add(new HttpCookie(_cookieName, value.ToString()));
}
}
}
The image below shows the setup in the Marketing Centre with each test variable pointing at the relevant node.

Now I just need to setup the Sample Rendering to use the test on the homepage:

So publishing the site and doing a couple of refreshes we can see that the content of the sample rendering actually changes. So are multivariate test works!!

Ok so it works for XSLTs but what about a sublayout? Si I have created a simple sublayout with the following code behind:
public partial class layouts_MVTest : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
output.Text = "Sublayout: " + Sitecore.Context.Item["Title"];
}
}
I have also updated the home item to include the sublayout and set the sublayout to use the multivariate test:

Ok so saving this and publishing it we now get this output:

Notice how the XSLT content changes but the sublayout content does not change. So why does this happen? This is caused by how the Sublayouts and XSLTs resolve the current item.
I suspect that most Sitecore developers (this is true of where I work and for myself) are used to getting the current item via Sitecore.Context.Item within a sublayout. However if you look at the code that the XSLT uses to render itself (Sitecore.Web.UI.WebControls.XslFile there is a GetItem method inherited from the Sitecore.Web.UI.WebControl class. Within this method the actual item passed to the XSLT is resolved based on the WebControl.DataSource property. The Multivariate Test actually changes the DataSource property to point at the new content item.
So how do we get this value in the our Sublayout? Well we have actually look at the parent control of our user control:
Sitecore.Web.UI.WebControls.Sublayout parent = (Sitecore.Web.UI.WebControls.Sublayout)this.Parent; string sourceItem = parent.DataSource;
This then gives us the ID of the item injected by the multivariate tests. So what does this mean in terms of development? Well if you want to use multivariate tests on a site that you already developed you will have to replace any reference to Sitecore.Context.Item with a custom solution that looks at the parents DataSource property:
public Item Source
{
get
{
Sitecore.Web.UI.WebControls.Sublayout parent = (Sitecore.Web.UI.WebControls.Sublayout)this.Parent;
Guid sourceItem = new Guid(parent.DataSource);
return Sitecore.Context.Database.GetItem( new Sitecore.Data.ID(sourceItem)) ?? Sitecore.Context.Item; }
}
What about sub-items, for example you have the following code in your XSLT:
<ul>
<xsl:for-each select="./item">
<li>
<sc:text field="Title"></sc:text>
</li>
</xsl:for-each>
</ul>
Well this actually just breaks as shown in this images below and only works when the original item is requested. The solution is to proxy the subitems below the new nodes:

I have summarised the problems you will have to think about when using mutlivariate tests on your site:
The multivariate tests are a powerful addition to the Sitecore platform but if you plan to use them on your site you need to think how they will be used before you start coding. Their usage will determine how you design both your renderings and sublayouts. For simplicity it is best to only use multivariate tests on renderings and sublayouts that only have a dependency on the current item.
Aug 27th
This blog has been migrated, original date 22 Feb 2010
I had written a previous blog about setting up a default language for Sitecore, however this was for Sitecore 5.3.x . The Sitecore 6 API is slightly different. I have detailed the Sitecore 6 solution below.
Firstly create the following class:
public class SqlServerDataProvider : Sitecore.Data.SqlServer.SqlServerDataProvider
{
public SqlServerDataProvider(string connectionString)
: base(connectionString)
{
}
protected override void LoadItemFields(string itemCondition, string fieldCondition, object[] parameters, Sitecore.Collections.SafeDictionary prefetchData)
{
base.LoadItemFields(itemCondition, fieldCondition, parameters, prefetchData);
//set the default language to use
Language defaultLang;
Language.TryParse("en", out defaultLang);
//full list of languages the site uses
LanguageCollection coll = this.GetLanguages();
foreach (var data in prefetchData)
{
if (data.Value != null)
{
var uris = data.Value.GetVersionUris();
//check the item contains the default language before doing anything
if (uris.Cast().Any(x => x.Language == defaultLang))
{
//get the default language fields
var defaultUri = uris.Cast().First(x => x.Language == defaultLang);
//loop through each language
foreach (Language lang in coll)
{
//check if language doesn't exist
if (!uris.Cast().Any(x => x.Language == lang))
{
//update language with default language values
FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
foreach (var key in fields.GetFieldIDs())
{
data.Value.AddField(lang.Name, 1, key, fields[key]);
}
}
}
}
}
}
}
}
The main difference is the change in the for loop. In Sitecore 5.3.x the GetFieldsList method returned a collection of field objects that had two properties, the Key which was the field name and a Value property. This has been replaced with an object that wraps a HashList of ID’s and Values. This makes more sense since field names could be change and break code but ID’s will be consistent.
FieldList fields = data.Value.GetFieldList("en", defaultUri.Version.Number);
foreach (var key in fields.GetFieldIDs())
{
data.Value.AddField(lang.Name, 1, key, fields[key]);
}
The XML describing the data provider in the web.config has also changed, add the provider detailed below:
<dataproviders>
<main type="Sitecore.Data.$(database).$(database)DataProvider, Sitecore.Kernel">
<param connectionstringname="$(1)">
<name>$(1)</name>
</main>
<web type="Demo.Sitecore.SqlServerDataProvider, Demo">
<param connectionstringname="$(1)">
<name>$(1)</name>
</web>
</dataproviders>
Then alter the provider used by the database from:
<database id="web" singleinstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
<param desc="name">$(id)
<icon>Network/16x16/earth.png</icon>
<securityenabled>true</securityenabled>
<dataproviders hint="list:AddDataProvider">
<dataprovider ref="dataProviders/main" param1="$(id)">
</dataprovider></dataproviders></database>
An update the the provider to:
<param desc="name">$(id)Â Â <icon>Network/16x16/earth.png</icon>Â Â <securityenabled>true</securityenabled>Â Â <dataproviders hint="list:AddDataProvider"> Â Â Â <dataprovider ref="dataProviders/web" param1="$(id)"> </dataprovider> </dataproviders>
Aug 27th
This post has been migrated, original date 04 Jan 2009
This script creates a SQL Server database user for the Sitecore 6.2 databases manually. You will need to find and replace %username% and %password% with your values.
CREATE LOGIN %username% WITH PASSWORD = '%password%' USE Sitecore_Master GO CREATE USER %username% FOR LOGIN %username% GO GRANT EXECUTE TO %username% GO sp_addrolemember 'db_datareader', '%username%' GO sp_addrolemember 'db_datawriter', '%username%' GO USE Sitecore_Web GO CREATE USER %username% FOR LOGIN %username% GO GRANT EXECUTE TO %username% GO sp_addrolemember 'db_datareader', '%username%' GO sp_addrolemember 'db_datawriter', '%username%' GO USE Sitecore_Master GO CREATE USER %username% FOR LOGIN %username% GO GRANT EXECUTE TO %username% GO sp_addrolemember 'db_datareader', '%username%' GO sp_addrolemember 'db_datawriter', '%username%' GO
Aug 27th
This post has been migrated, original date 22 Dec 2009
If you want to be able to get all the attributes on an XML element including their names you can use the following XSTL:
<xsl:for-each select="./@*"> <xsl:value-of select="name()"> - <xsl:value-of select="."><br> </xsl:value-of> </xsl:value-of> </xsl:for-each>
Aug 27th
This post has been migrated, original date 11 Nov 2009
The embed HTML element is not a valid XHTML element, this creates a problem when you want to insert objects into your Rich Text fields such as You Tube videos. To validate XHTML sitecore uses the file /sitecore/shell/schemas/sitecore xhtml.xsd. By editing this file we can allow usage of the embed element.
Beneath the /xs:schema node add a definition for the embed element:
<xs:element name="embed">
<xs:complexType mixed="true">
<!-- from http://www.htmlref.com/Reference/AppA/tag_embed.htm -->
<xs:attribute name="align" type="xs:string" />
<xs:attribute name="alt" type="xs:string" />
<xs:attribute name="class" type="xs:string" />
<xs:attribute name="code" type="xs:string" />
<xs:attribute name="codebase" type="xs:string" />
<xs:attribute name="height" type="xs:string" />
<xs:attribute name="hspace" type="xs:string" />
<xs:attribute name="id" type="xs:string" />
<xs:attribute name="language" type="xs:string" />
<xs:attribute name="name" type="xs:string" />
<xs:attribute name="src" type="xs:string" />
<xs:attribute name="style" type="xs:string" />
<xs:attribute name="title" type="xs:string" />
<xs:attribute name="unselectable" type="xs:string" />
<xs:attribute name="vspace" type="xs:string" />
<xs:attribute name="width" type="xs:string" /
<!-- used by you tube -->
<xs:attribute name="type" type="xs:string" />
<xs:attribute name="allowscriptaccess" type="xs:string" />
<xs:attribute name="allowfullscreen" type="xs:string" />
</xs:complexType>
</xs:element>
This definition was created based on the attributes list at http://www.htmlref.com/Reference/AppA/tag_embed.htm and some attributes used by You Tube. You may need to define additional attributes as needed.
Next we need to add a reference to the new embed definition in the object definition. Find the definition and replace the first part with the following which has the embed reference:
<xs:element name="object">
<xs:complexType mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="embed" />
<xs:element ref="param" />
<xs:group ref="block" />
<xs:element ref="form" />
<xs:group ref="inline" />
<xs:group ref="misc" />
</xs:choice>
...
Save the file and your embed element problems should disappear. Remember however that doing this will mean that your site is no longer XHTML strict.