Blog has moved!

March 31, 2011

I have now moved my blog to http://www.cmssource.co.uk/blog


Setting up a Sitecore project works with both versions 5.3 and 6

October 6, 2008

Sitecore(SC) has a decent article on how to set up a Sitecore project on Visual Studio. This is a pretty good start but it does not quite meet our company’s requirements.

In this blog post I will attempt to tell you exactly how a structure a project assuming that you have the following requirements for your SC environment:

  • You need to have multiple websites running on one instance of SC and you want each website to have its own Visual Studio project.
  • You are not using a virtual folder per website.
  • You want to manage multiple Class Library/Child projects within each website project.
  • You want to keep the Renderings, Sub-layouts, Layouts, Associated files (css, js etc) and DLL’s of each website independent.

Our company has worked with multiple projects in Sitecore v5.3 and we have also Started a new project using Sitecore v6 (Visual Studio 2005 and 2008). I can safely say that we have come up with a tried and proven project structure that I can recommend that everyone can and should use. Please follow the SC developer cookbook if you are only going to ever have one website running on your instance of SC.

There is a fair bit to write on this entry and I will be slowly updating it, if anyone is in desperate need to this information right now then please leave a comment and I will try to speed things up!

Read the rest of this entry »


Sitecore and Telligent Community Integration

March 29, 2010

You may have read the following article:

http://www.cmswire.com/cms/web-cms/sitecore-and-telligent-integrate-for-better-online-engagement-005991.php

This claims that Sitecore and Telligent have integrated to make a convenient solution combining the power of a social networking/collaboration platform with the flexibility of a CMS system.

There is a fairly complicated white-paper that has been published by Sitecore which is split into two parts:

  1. Security Integration
  2. Content management integration

This solution is not as straight forward as it sounds and it is very poorly supported . . . . I strongly suggest that you do not waste your time heading down this path if you can avoid it. It provides a way for you to use community functionality within a Sitecore site (not the other way around  . . . in case you were thinking about pulling Sitecore content into a community site). The solution is out dated and will not work with the latest versions of Sitecore.

We needed to Drive a Community server site and pull Content + Media out of Sitecore which will be used within Telligent community server via Widgets. We also embedded content from Sitecore directly into some of the community theme aspx files. The Community server web site also needed the ability to upload media items directly into Sitecore.

I found that the best method to pull out content from Sitecore into another web application is via a Web Service or potentially a REST service which will run within the Sitecore web application. This will give you the access required to Update/Create Sitecore content via a separate web application.


ASP.NET service faulting error Sitecore 6 workaround

October 5, 2008

We have sitecore 6 environments working on Virtual Machines (VM’s). Sitecore 6 seems to cause an ASP error at seemingly random intervals leading to a total loss of service 9only on VM’s. Event Viewer will show you the following error:

Event Type: Error
Event Source: Application Error
Event Category: (100)
Event ID: 1000
Date:  8/8/2008
Time:  4:09:35 PM
User:  N/A
Computer: SCTEST
Description:
Faulting application w3wp.exe, version 6.0.3790.3959, faulting module unknown, version 0.0.0.0, fault address 0x709a2075.

Sitecore have provided a work-around for this. Set the following web.config entry to ‘false’ as show below:

<!–  ENABLE COUNTERS
Indicates if performance counters are enabled.
Default value: true
–>
<setting name=”Counters.Enabled” value=”false” />

We have made this change and it seems to get rid of the issue. Seems like Sitecores backend performance monitoring may be using some .NET 3.5 functionality that causes this error (this is just a guess).

See the SC forum for more details:

http://sdn5.sitecore.net/forum/ShowPost.aspx?PostID=11838#11838


How to destroy a cookie C#.NET

February 5, 2008

Basically have to set its expire date to the past! (the cookies we created for our site lasted a day so -1d was enough for this example)

public void DestroyCookie(string cookieName)

    {

        if (HttpContext.Current.Request.Cookies[cookieName] != null)

        {

            HttpCookie myCookie = new HttpCookie(cookieName);

            myCookie.Expires = DateTime.Now.AddDays(-1d);

            HttpContext.Current.Response.Cookies.Add(myCookie);

        }

    }


Use your own Authentication

February 5, 2008

I didnt want to use Forms Authentication once and I decided to make my own password hashing just for the hell of it, here is a very simple implementation.
The goal was to save a user and the users password as a hash + a random salt string for increased security.
Also wanted to be able to generate a new password and have a hash + salt created for that new password I generated as can be seen from the following interface Crypto.cs.
Note: Yay downloaded a tool that actually Generated HTML from my code properly!! from here.

using System;

using System.Collections.Generic;

using System.Text;

 

namespace PassEncrypt

{

    interface Crypto

    {

        /// <summary>

        ///  Gets the Hash key and Salt for a specific

        ///  password. 

        /// </summary>

        /// <returns>

        /// Will return a string with three elements      

        ///    1. Hash Key

        ///    2. Salt

        /// </returns>

        string[] GenerateKeySalt( string plainTxtPass );

 

 

        /// <summary>

        ///  Change the password.

        /// 

        /// </summary>

        /// <returns>

        /// Will return a string with three elements

        ///    1. New Password

        ///    2. Hash Key

        ///    3. Salt

        /// </returns>

        string[] GenerateNewPassword();

 

        string GetHashKey(string input);

 

    }

}

And now to implement this interface with the Encrypt.cs class (p.s. Man I am lowing this new HTML generation from Code tool):

using System;

using System.Collections.Generic;

using System.Text;

using System.Security.Cryptography;

 

namespace PassEncrypt

{

    public class Encrypt : Crypto

    {

 

        #region Generate the Hash key and salt for a given password

 

        /// <summary>

        /// Returns a salt value and a hash key to be stored

        /// in the database for the given user.

        /// </summary>

        /// <param name=”plainTxtPass”></param>

        /// <returns></returns>

        public string[] GenerateKeySalt(string plainTxtPass)

        {

            string[] s = new string[2];

 

            string salt = GenerateRandomSalt();

            string passAndSalt = plainTxtPass + salt;

            string hash = GetHashKey(passAndSalt);

 

            s[0] = hash;

            s[1] = salt;

            return s;

        }

 

        #endregion

 

        #region Generate a new password

 

        /// <summary>

        /// Generates a new random password and returns a string array with:

        ///    1. new password

        ///    2. hash key

        ///    3. salt value

        /// </summary>

        /// <returns></returns>

        public string[] GenerateNewPassword()

        {

            string[] s = new string[3];

 

            RandomPassword randPassGenerator = new RandomPassword();

 

            string newPass = randPassGenerator.GetPassword();     

            string salt = GenerateRandomSalt();

            string passAndSalt = newPass + salt;

            string hash = GetHashKey(passAndSalt);

 

            s[0] = newPass;

            s[1] = hash;

            s[2] = salt;

 

            return s;

        }

 

        #endregion

 

        #region Generate random salt

 

        /// <summary>

        /// Generates a cryptographically strong salt string

        /// </summary>

        /// <returns></returns>

        public string GenerateRandomSalt()

        {

            RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();

            byte[] saltInBytes = new byte[5];

            crypto.GetBytes(saltInBytes);

 

            return Convert.ToBase64String(saltInBytes);

        }

 

        #endregion

 

        #region Get the hash key for a given string

 

        public string GetHashKey(string input)

        {           

            byte[] tmpSource;

            byte[] tmpHash;

 

            //Convert input to a Byte Array (needed for hash function)

            tmpSource = ASCIIEncoding.ASCII.GetBytes(input);

 

            //Compute hash based on source data.

            tmpHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);

 

            return Convert.ToBase64String(tmpHash);

        }

 

        #endregion

 

    }

}

The following class (RandomPassword.cs) contains my Random password generator. You may want to modify it according to the type of password you would like to generate:

using System;

using System.Collections.Generic;

using System.Text;

 

namespace PassEncrypt

{

    class RandomPassword

    {

        private int RandomNumber(int min, int max)

        {

            Random random = new Random();

            return random.Next(min, max);

        }

 

 

        /// <summary>

        /// Generates a random string with the given length

        /// </summary>

        /// <param name=”size”>Size of the string</param>

        /// <param name=”lowerCase”>If true, generate lowercase string</param>

        /// <returns>Random string</returns>

        private string RandomString(int size, bool lowerCase)

        {

            StringBuilder builder = new StringBuilder();

            Random random = new Random();

            char ch;

            for (int i = 0; i < size; i++)

            {

                ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));

                builder.Append(ch);

            }

            if (lowerCase)

                return builder.ToString().ToLower();

            return builder.ToString();

        }

 

 

        public string GetPassword()

        {

            StringBuilder builder = new StringBuilder();

            builder.Append(RandomString(4, true));

            builder.Append(RandomNumber(1000, 9999));          

            return builder.ToString();

        }

 

    }

 

}

Thats all there is to it. I just made this is a class library project names PassEncrypt.

crypto-project.jpg

Just reference PassEncrypt and:
For a new user send their password in and get an array containing the [hash,salt],  store these somewhere and associate them with the username:

    #region Get Hashed password

    public bool GetHashPassword(string username, string password)

    {

        Encrypt crypt = new Encrypt();

        string user = username;

        string pwd = password;

        string salt = “”;

        salt = dataService.GetUserSalt(user);

 

            if (salt != “”)

            {

                string passHash = dataService.GetUserHash(user);

 

                string resultHash = crypt.GetHashKey(pwd + salt);

 

 

                if (passHash == resultHash)

                { //Password Correct

                    return true;

                }

                else

                {

                    return false;

                }

            }

            else

                return false;

    }

    #endregion


Sitecore – Store Multilist related content within local item on save

February 5, 2008

The Requirement

Our clients have ‘subject’ and ‘function’ Metadata fields within their web page. They wanted to be able to content manage this subject and function list . They then wanted to be able to assign a subset of these function and subject keywords into each web page item (so all the subjects and functions are common to the whole site).

The Problem

The cleanest solution to this problem was to define a bunch of simple text items for each of the subjects and functions within specfic folder items. We would then create two multi lists in the Metadata base template (one for subject and one for function) and point them at these respective source directories.

Now think of the situation:  We have 5 subjects and 3 functions on average per web page. In the background, we are going to have to pull out data from 8 related content items every time we load a given page. We did not want to do this so we devised a simple work-around that would let us retain the useability of the method discussed above but also ave all this related content available on the one item when it needs to be served up.

The Solution (I will be using a simple ‘Category’ multilist example as a demo here)

We added two hidden (not visible to author) text field within the Metadata base template to correspond with each multilist. These two text fields will contain the content (not the Id’s) of the ‘Description’ field of the referenced items seperating each with a ‘|’ delimeter as can be seen below.

 multilistcontentfieldshiddenfield.jpg

 The categories associate to a simple text field item which must have a field named ‘Description’ within it:

 categoriesitem-template.jpg

All the categories should lie within a common folder item so that we can point our multilist source at that folder:

categoriescontenttree.jpg

In the template that holds the multilist, make sure that you create a text field with the name ‘chosen ‘ + <multilist name>. I.e. in our example, our multilist is named ‘Categories’, so our hidden text field will be called ‘Chosen Categories’

 multilistreferencetemplate.jpg

Now we create an OnSaving event which does the following:

1. Check if the item thats being saved contains any multilists

 2. If 1 = true, then for each multilist named <name> in the current item

3. Check if there is a field named ‘Chosen ‘ + <name> (of the current multilist) from 2

4. If 3 = true, then clear the ‘Chosen ‘ + <name> field of its content; retrieve all the items referenced by the current multilist; For each of these items check if a ‘Description’ field exists; if ‘Description’ exists and there is content within it, add this content to ‘Chosen ‘ + <name>

I have pasted the code for the ItemOnSavingEvents.cs class here (sorry about the indentation, copy/paste into blog isnt the best):

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Sitecore;
using Sitecore.Data.Events;
using Sitecore.Data;
using System.Collections;  

namespace SitecoreSCD1Labs
{
    public class ItemOnSavingEvents
    {
        public void OnItemSavingPopulateHidenFields(object sender, EventArgs args)
        {
            Sitecore.Data.Items.Item item = Sitecore.Events.Event.ExtractParameter(args, 0) as Sitecore.Data.Items.Item;
           
            Sitecore.Collections.FieldCollection fields = item.Fields;

            foreach( Sitecore.Data.Fields.Field field in fields ) {
                if (field.Type == “multilist”)
                {
                    Sitecore.Data.Fields.MultilistField mlf = (Sitecore.Data.Fields.MultilistField)field;
                    String fieldname = field.Name;

                    if( item.Fields[“chosen ” + fieldname] != null ) { //Hidden field for corresponding multilist exists
                        Sitecore.Data.Fields.Field hiddenField = item.Fields[“chosen ” + fieldname];
                        hiddenField.SetValue(“”, false);


                        //Populate the hidden field with the descriptions from the related items (pipe delimitered)
                        String[] relatedItemGuids = mlf.Items;
                         
                        foreach (String guid in relatedItemGuids)
                        {
                            Sitecore.Data.Database currentDB = Sitecore.Configuration.Factory.GetDatabase(“master”);
                            Sitecore.Data.Items.Item relatedItem = currentDB.Items.GetItem(guid);
                            if (relatedItem != null)
                            {
                                if (relatedItem.Fields[“description”] != null)
                                    if (hiddenField.ToString() == “”)
                                        hiddenField.SetValue(relatedItem.Fields[“description”].ToString(), false);
                                    else
                                        hiddenField.SetValue(hiddenField.ToString() + “|” + relatedItem.Fields[“description”].ToString(), false);
                            }
                        }      
                    }
                }
            }
        }
    }
}
 Add a web.config entry in the Item onsave event to run your code:<event name=”item:saving”>
   <handler type=”SitecoreSCD1Labs.ItemOnSavingEvents, SitecoreSCD1Labs” method=”OnItemSavingPopulateHidenFields” />
  </event>
Drawbacks of this solutionUnfortunately if the content author changes an existing subject or function then the current items will not automatically change to reflect the new update. The new change will only get reflected on existing items once those items get edited for any reason and re-saved (I have found that some edit needs to be made, i.e. even a smal re-sort of one of the metadata multilist fields, otherwise the item:onsave event does not fire even if save is clicked). In our case the user will most likely only add new subjects and functions and not change existing ones.