Force clients to refresh JS/CSS files

It’s a common problem with an easy solution. You make some changes to a JavaScript of CSS file, but your users still report an issue due to the old version being cached.

You could wait for the browsers cache to expire, but that isn’t a great solution. Worse if they have the old version of one file and the new version of another, there could be compatibility issues.

The solution is simple, just add a querystring value so that it looks like a different path and the browser downloads the new version.

Manually updating that path is a bit annoying though so we use modified time from the actual file to add the number of ticks to the querystring.


DefaultLayout.cshtml

using Utilities;
using UrlHelper = System.Web.Mvc.UrlHelper;

namespace Web.Mvc.Utils
{
    public static class UrlHelperExtensions
    {
        public static string FingerprintedContent(this UrlHelper helper, string contentPath)
        {
            return FileUtils.Fingerprint(helper.Content(contentPath));
        }
    }
}

UrlHelperExtensions.cs

using System;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;

namespace Utilities
{
	public class FileUtils
    {
        public static string Fingerprint(string contentPath)
        {
            if (HttpRuntime.Cache[contentPath] == null)
            {
                string filePath = HostingEnvironment.MapPath(contentPath);

                DateTime date = File.GetLastWriteTime(filePath);

                string result = (contentPath += "?v=" + date.Ticks).TrimEnd('0');
                HttpRuntime.Cache.Insert(contentPath, result, new CacheDependency(filePath));
            }

            return HttpRuntime.Cache[contentPath] as string;
        }
    }
}

FileUtils.cs

Using Datasources

A few weeks ago I blogged about Databinding to the a datasource rather than the context in Sitecore. Today I spotted this excellent video from Martina on the Master Sitecore YouTube channel. It’s only focused on MVC, but gives a good explanation of what DataSources are and how you can use them. With an extra tiny bit of information on using them for personalization and testing at the end.

Sitecore: Data binding to a datasource rather than the context

By default when you place a Sitecore control. e.g. on a page it will bind to the pages context item even if the rendering has had a Data Source set against it.

MVC – View Renderings

If your Sitecore solution is MVC based and you are using a View Rendering then this is simple. Make sure your view’s model is set to Sitecore.Mvc.Presentation.RenderingModel and then pass Model.Item as the item parameter to the Sitecore HTML helper function for rendering a field.

@using Sitecore.Mvc
@using Sitecore.Mvc.Presentation

@model Sitecore.Mvc.Presentation.RenderingModel

<div>
    <h2>@Html.Sitecore().Field("Title", Model.Item)</h2>
    <div>@Html.Sitecore().Field("Content", Model.Item)</div>
</div>

WebForms – Sublayouts

However if your Sitecore solution is using WebForms with sub-layouts then thing’s get a little trickier. Unlike with the View Rendering there is no equivalent of Model.Item so a bit of work is required to get the Data Source Item.

If you check to see if the controls parent is a sublayout, you can then cast it as a sublayout and access the datasource property from their. You will then need to set the Item property of each of the Sitecore Controls in your sublayout. In this example the Sitecore Control is being referenced by controlId in the code.

Item DataSource;
if (Parent is Sublayout)
   DataSource = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);

controlId.Item = DataSource;

Sitecore MVC Page Editor: Combining a General Link with an Image

Sitecore Page Editor

Sitecore’s Page Editor provides content authors a simple way to edit content, visually seeing the changes as they make them. To make fields on a page editable though the Page Editor simply use the field renderer function to put a field’s content on the page. When the page is viewed in page editor mode the function will output all the necessary html and javascript to make the page editor functionality work.

@Html.Sitecore().Field("Title", Model.Item)

But what if your page needs to render the contents of one field inside another? e.g. You could have a link on an image or a link surrounding a combination of other fields.

In an xslt rendering you could simply nest one tag within another:

<sc:link field="Image Link">
   <sc:image field="Image" />
</sc:link>

When you click the item in the Page Editor the toolbar would then combine the icons for the General Link field and the Image field so that you can edit the image and update the link. But with a ViewRendering in MVC, the Razer syntax used for views doesn’t support nesting items in this way.

Thankfully Sitecore have considered this and rather than using the Field function they have included a BeginField and EndField function. Between the two you can place your nested fields:

@Html.Sitecore().BeginField("Image Link", Model.Item)
    @Html.Sitecore().Field("Image", Model.Item)
@Html.Sitecore().EndField()

Unfortunately it doesn’t quite work right. The page will render correctly and the toolbar will show both options, however editing anything results in the content disappearing until you refresh the page. Thankfully there is a work around to get it to work:

@Html.Sitecore().BeginField("Image Link", Model.Item, new { haschildren = true })
    @Html.Sitecore().Field("Image", Model.Item)
@Html.Sitecore().EndField()