SharePoint user control to display a random image

The master page of a SharePoint site I work on loaded 7 photographic images, all over 50 kB each, to display at random as a banner adjacent to the site logo. The way it loaded the images was very inefficient: a default image was loaded in the HTML, and Javascript on the page created 7 image objects and returned one at random to overwrite the default. I decided to find a C# way to solve the problem.

Here is the original Javascript code:

<script language="javascript" type="text/javascript">
    var bannerImages = new Array();
    var bannerIndex = 0;
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "building.jpg";
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "tree.jpg";
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "fountain.jpg";
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "people.jpg;
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "painting.jpg;
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "statue.jpg;
    bannerImages[bannerIndex] = new Image();
    bannerImages[bannerIndex++].src = "cafe.jpg;
    var randombannerIndex = Math.floor(Math.random() * bannerImages.length);
    document.images["banner"].src = bannerImages[randombannerIndex].src;
</script>

Creating image elements caused each file to be downloaded by the browser, meaning that 6 images were loaded that were never displayed to the user! It was also visually jarring, because the default image would be displayed momentarily before the selected random image was loaded.

My quick fix was to adjust the Javascript. Instead of creating new image elements, I selected a filename at random and updated the existing source:

<script language="javascript" type="text/javascript">
    var bannerImages = [
        "building.jpg",
        "tree.jpg", 
        "fountain.jpg", 
        "people.jpg", 
        "painting.jpg", 
        "statue.jpg", 
        "cafe.jpg"];
    document.images["banner"].src = 
        bannerImages[Math.floor(Math.random() * bannerImages.length)];
</script>

That was a decent improvement, but it still loaded an unneeded image, and the default image was still momentarily visible.

The site is running SharePoint 2010, so I decided to replace the Javascript by creating a user control. This is only the 2nd user control I’ve created, so I’ll be fairly detailed with the steps:

  1. In Visual Studio 2010, create a new Empty SharePoint project. I called mine RandomImage, and set it to deploy as a farm solution.
  2. Right-click the project properties and select Add — New Item — User Control. I named mine RandomImageUserControl.ascx.
  3. Expand the new RandomImageUserControl.aspx to access the code-behind file, RandomImageUserControl.aspx.cs.

Here’s the code I added to the code-behind file:

{
    public partial class RandomImageUserControl : UserControl
    {
        protected override void Render(HtmlTextWriter writer)
        {
            // Array of file names
            string[] strArray = new string[] { 
                "building.jpg", 
                "tree.jpg", 
                "fountain.jpg", 
                "people.jpg", 
                "painting.jpg", 
                "statue.jpg", 
                "cafe.jpg" };

            // Create a random-number generator object
            Random randomIndex = new Random();
            // Randomly select one of the images from the array
            String imageSrc = images[randomIndex.Next(0, images.Length)];

            // Create and render an img element
            writer.AddAttribute(HtmlTextWriterAttribute.Src, imageSrc);
            writer.AddAttribute(HtmlTextWriterAttribute.Alt, "");
            writer.RenderBeginTag(HtmlTextWriterTag.Img);
            writer.RenderEndTag();
        }
    }
}

I deployed it to my testing server, and added the following to the site master page just above the doctype declaration:

<%@ Register 
    TagPrefix="customuc" 
    TagName="RandomImage" 
    Src="~/_controltemplates/RandomImage/RandomImageUserControl.ascx" %>

And I added this in place of the default image tag:

<customuc:RandomImage 
    id="RandomImage" 
    runat="server"></customuc:RandomImage>

Voila! It worked. But I had some reservations about it. What if we needed to update the images later on? Would we really want to edit, recompile, and redeploy a user control just to change an image reference?

I decided to re-write the user control to accept the image filenames as parameters:

namespace RandomImage.CONTROLTEMPLATES.RandomImage
{
    public partial class RandomImageUserControl : UserControl
    {

        public string imageList { get; set; }

        protected override void Render(HtmlTextWriter writer)
        {
            // Split comma-delimited list of image paths into string array
            string[] images = imageList.Split(',');

            // Create a random-number generator object
            Random randomIndex = new Random();
            // Randomly select one of the images from the array
            String imageSrc = images[randomIndex.Next(0, images.Length)];

            // Create and render an img element
            writer.AddAttribute(HtmlTextWriterAttribute.Src, imageSrc);
            writer.AddAttribute(HtmlTextWriterAttribute.Alt, "");
            writer.RenderBeginTag(HtmlTextWriterTag.Img);
            writer.RenderEndTag();
        }
    }
}

I updated the call to the user control on the master page:

<customuc:RandomImage 
    id="RandomImage" 
    imageList="building.jpg,
            tree.jpg,
            fountain.jpg,
            people.jpg,
            painting.jpg,
            statue.jpg,
            cafe.jpg" 
    runat="server"></customuc:RandomImage>

I was pleased with this, so I tried to deploy it to the staging server. Deploying it from within Visual Studio was simple–just right-click the project and select Deploy. Visual Studio takes care of everything. The issue with software that automates everything is that you don’t always know what it is doing. The staging server doesn’t have Visual Studio on it, though. How does a user control get installed?

I tried copying the DLL (RandomImage.dll) into the General Assembly Cache (aka “the GAC”, located at C:\Windows\assembly), and copying the user control file into the 14 hive (14/TEMPLATE/CONTROLTEMPLATES/RandomImage/RandomImageUserControl.aspx). When I registered the user control and added the call to the user control to the master page, I got the following error:

Could not load file or assembly '$SharePoint.Project.AssemblyFullName$' or one of its dependencies. The system cannot find the file specified.

The right way (or a right way, at least) is to deploy a .wsp file to the server:

  1. I packaged the solution with Visual Studio (right-click the project and select Package)
  2. Using the SharePoint Administrator Management Shell, I added the solution:
    Add-SPSolution S:\RandomImage\bin\Release\RandomImage.wsp
  3. Open SharePoint Central Admin and go to System Settings — Manage Farm Solutions
  4. Click randomimage.wsp and Deploy Solution

A fair amount of effort to replace the clunky, but working, Javascript. I think it’s worth it, though, for a speedier and improved user experience. If you have any comments, or suggestions as to how to improve the code, let me know!

One thought on “SharePoint user control to display a random image”

  1. A note for those who may need to update a solution package:

    You can’t add a solution that already exists in the solution store. You can’t remove a solution that has been deployed.

    First, retract the solution. You can do this through Central Admin, or the Uninstall-SPSolution in the SharePoint management shell.

    Next, remove the solution (either via Central Admin or the Remove-SPSolution command).

    Now that the old solution has been removed, you can add the latest version. (Once added, you can install it from the management shell using the Install-SPSolution command.)

    For a list of feature and solution commands, see: http://technet.microsoft.com/en-us/library/ee906565.aspx

Leave a Reply

Your email address will not be published. Required fields are marked *