Cache Busting Using CssRegistration & ScriptLink in SharePoint 2010

What is cache busting?

Cache busting is way to ensure that the browser will download a new version of your file. This is easily accomplished using a simple technique of appending a ? with some unique characters at the end.

ex:

<link rel="stylesheet" href="/css/example.css?v1.0" type="text/css" />

The browser sees this as a different file and will then download and cache this new file. Each time the browser see’s a different string it will download the file and cache it. Some methods use a revision number, a date, random number, or a signature as a query string parameter. Taking a look at the example above you will see a version number is specified at the end of the .css file to do the cache busting.

SharePoint 2010 uses a technique which involved computing a MD5 hash signature of the file and appending a ?rev={MD5HASH} to the link. This technique works very well because the computed hash won’t change unless you change something in the file.  Also the computed MD5 hash will be unique to ensure that the file will appear new to the browser. For all you super technical people, yes MD5 is not guaranteed to be unique, there is a very very small chance of the hash being the same. This technique of the computed MD5 hash signature is used for both CssRegistration and ScriptLink in SharePoint 2010. If you are interested in more detail then reflect into Microsoft.SharePoint.dll –> Microsoft.SharePoint.Utilities –> SPUtility –> MakeBrowserCacheSafeLayoutsUrl

Cache busting for CssLink

When using CssRegistration the files need to be relative to the Layouts folder, more specifically LAYOUTS\1033\STYLES\{CssFile}.

image

image

If you do not keep the files in the LAYOUTS\1033\STYLES then you will receive an error

image

Below is the rendered html output of the CssRegistration tag above

image

You can see that “/_layouts/1033/styles/” is prepended to the ‘Name’ property provided in the CssRegistration tag and your .css file is successfully cache safe.

Cache busting for ScriptLink

When using ScriptLink the files need to be relative to the Layouts folder. Unlike the CssRegistration, ScriptLink has a property called ‘Localizable’.  In the asp tag below I specify Localizable=”False”

If you don’t specify Localizable=”False” then you need to put the files relative to the Layouts\1033 folder.

image

image

Below is the rendered html output of the ScriptLink tag above

image

You can see that the “/_layouts/” is prepended to the ‘Name’ property provided in the ScriptLink tag and your .js file is successfully cache safe.

What if I am deploying files to the Style Library?

In the scenario where you are deploy CSS to the Site Collection style library then there is no automated way of using the SharePoint cache busting from the CssLink, however you can take a look at Chris O’Brien’s posting – Avoiding bugs from cached JavaScript and CSS files in SharePoint. In this posting he has a solution in which he creates a new class inheriting from CssLink and adds his own mechanism of cache busting. He also mentions that there is no equivalent way to do the same for JavaScript files stored in the content db.

Summary

SharePoint 2010 provides an easy way to do cache busting on CSS and JS files stored in the LAYOUTS folder.

If you store your files in the ‘Style Library’ or content DB then you have to revert to manual methods or get creative with your own solutions.

Deploying a custom ‘Composed Look’ in SharePoint 2013

There are two ways to deploy your custom composed look. Via XML / Elements file – the declarative way, or via feature receiver / C# the imperative way.

This article will cover both methods, it’s up to you to ultimately decide which way you prefer.

First I will explain how to put together the the Visual Studio 2012 project with the assets for the composed look. If you already know how to deploy these assets or they already exist in SharePoint skip down to the bottom.

The Project

Starting with an empty SharePoint Project – farm solution.

First we need to add 4 things which are used by the Composed Look.

  • Master Page
  • Theme (Colors)
  • Font Scheme (Optional)
  • Background Image (Optional)

Adding the Master Page

In the Visual Studio Project, right click the solution, select Add, select New Item

image

Select Module –> Name: MasterPage

image

In the MasterPage module, Delete the sample.txt

Copy in your masterpage

image

Edit the elements file, make it look like this.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="MasterPage" Url="_catalogs/masterpage">
    <File Url="MyMasterPage.master" Type="GhostableInLibrary" 
          Path="MasterPage\MyMasterPage.master" IgnoreIfAlreadyExists="true">
      <Property Name="UIVersion" Value="15" />
      <Property Name="ContentTypeId" Value="0x010105" />
    </File>
  </Module>
</Elements>

This completes this section.

Adding the Theme

In the Visual Studio Project, right click the solution, select Add, select New Item

image

Select Module –> Name: Theme

image

In the Theme module, Delete the sample.txt

Copy in your {theme}.spcolor

image

Edit the elements file, make it look like this.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Theme" Url="_catalogs/theme/15">
    <File Path="Theme\MyTheme.spcolor" Url="MyTheme.spcolor" 
          Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" />
  </Module>
</Elements>

This completes this section.

Adding the Font Scheme

In the Theme module, add in your {fontScheme}.spfont

image

Edit the elements file, make it look like this

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <Module Name="Theme" Url="_catalogs/theme/15">
    <File Path="Theme\MyTheme.spcolor" Url="MyTheme.spcolor" 
          Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" />

<File Path=”Theme\MyFontScheme.spfont” Url=”MyFontScheme.spfont”
Type=”GhostableInLibrary” IgnoreIfAlreadyExists=”TRUE” />

  </Module>
</Elements>

This completes this section.

Adding the Background Image

In the Visual Studio Project, right click the solution, select Add, select New Item

image

Select, SharePoint “Images” Mapped Folder [Alternatively you can deploy this to the layouts]

Add your background image to that folder

image

This completes this section.

Adding a Composed Look – the Declarative Method

In the Visual Studio Project, right click the solution, select Add, select New Item

image

Select Empty Element –> Name: MyComposedLook

image

Edit the elements file

Make sure to match up the MasterPageUrl, ThemeUrl, ImageUrl, FontSchemeUrl.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ListInstance FeatureId="{00000000-0000-0000-0000-000000000000}" 
                TemplateType="124" Title="Composed Looks" 
 Description="Use this list to store composed looks. These looks can be applied to this site by navigating to Site Settings and choosing Change the look." 
 Url="_catalogs/design" HyperlinkBaseUrl="http://intranet" RootWebOnly="FALSE">
    <Data>
      <Rows>
        <Row>
          <Field Name="ContentTypeId">0x0060A82B9F5D2F6A44A6A5723277B06731</Field>
          <Field Name="ID">100</Field>
          <Field Name="Title">My New Composed Look</Field>
          <Field Name="_ModerationStatus">0</Field>
          <Field Name="FSObjType">0</Field>
          <Field Name="FileLeafRef">2_.000</Field>
          <Field Name="Name">My New Composed Look</Field>
          <Field Name="MasterPageUrl">http://intranet/_catalogs/masterpage/MyMasterPage.master, /_catalogs/masterpage/MyMasterPage.master</Field>
          <Field Name="ThemeUrl">http://intranet/_catalogs/theme/15/MyTheme.spcolor, /_catalogs/theme/15/MyTheme.spcolor</Field>
          <Field Name="ImageUrl">http://intranet/_layouts/15/images/MyComposedLook/bg.gif, /_layouts/15/MyComposedLook/images/bg.gif</Field>
          <Field Name="FontSchemeUrl">http://intranet/_catalogs/theme/15/MyFontScheme.spfont, /_catalogs/theme/15/MyFontScheme.spfont</Field>
          <Field Name="DisplayOrder">1.0000000000000</Field>
        </Row>
      </Rows>
    </Data>
  </ListInstance>
</Elements>

image

This completes this section.

Adding a Composed Look – the Imperative Method

In the Visual Studio Project, right click the feature, select Add Event Receiver

image

Inside the FeatureActivated add the following

**This is experimental code, make sure to do your own testing if using**

        const string CustomLookName = "MyComposedLook";
        const string MasterPageUrl = "_catalogs/masterpage/MyMasterPage.master";
        const string ThemeUrl = "_catalogs/theme/15/MyTheme.spcolor";
        const string FontSchemeUrl = "_catalogs/theme/15/MyFontScheme.spfont";
        const string ImageUrl = "_layouts/15/images/MyComposedLook/bg.gif";

            var site = properties.Feature.Parent as SPSite;

            if (site != null)
            {
                var serverRelativeUrl = site.RootWeb.ServerRelativeUrl;
                SPList list = site.RootWeb.Lists["Composed Looks"];

                bool match = false;
                foreach (SPListItem listItem in list.Items)
                {
                    if (listItem.Name == CustomLookName)
                    {
                        match = true;
                    }
                }

                if (!match)
                {
                    SPListItem item = list.AddItem();

                    item["Title"] = CustomLookName;
                    item["Name"] = CustomLookName;

                    SPFieldUrlValue masterUrl = new SPFieldUrlValue();
                    masterUrl.Url = serverRelativeUrl + MasterPageUrl;
                    masterUrl.Description = serverRelativeUrl + MasterPageUrl;
                    item["MasterPageUrl"] = masterUrl;

                    SPFieldUrlValue themeUrl = new SPFieldUrlValue();
                    themeUrl.Url = serverRelativeUrl + ThemeUrl;
                    themeUrl.Description = serverRelativeUrl + ThemeUrl;
                    item["ThemeUrl"] = themeUrl;

                    SPFieldUrlValue imageUrl = new SPFieldUrlValue();
                    imageUrl.Url = "";
                    imageUrl.Description = "";
                    item["ImageUrl"] = imageUrl;

                    SPFieldUrlValue fontSchemeUrl = new SPFieldUrlValue();
                    fontSchemeUrl.Url = "";
                    fontSchemeUrl.Description = "";
                    item["FontSchemeUrl"] = fontSchemeUrl;

                    item["DisplayOrder"] = 100;
                    item.Update();
                }

                site.RootWeb.ApplyTheme(serverRelativeUrl + ThemeUrl, 
                                          null, null, true);
            }

Adding the Modules/Elements to the Feature

Double click on your feature, and ensure that the MasterPage & Theme are included in the feature.

If your using the declarative method for the Composed Look then make sure the MyComposedLook Element is in the feature.

If your using the imperative method then your feature receiver will do the work when activated.

Make sure that the Scope is set to Site

image

This completes this section.

Deploy and enjoy

SharePoint 2013– Design Manager – Unable to map network drive, while working on the server

I’ve been experimenting heavily lately with SharePoint 2013 and the entire process wrapped around Branding sites. I am one of those people that rely on working on the actual SharePoint server because I do branding and development.

Design Manager

image

Design Manager is the process of uploading your design files to your site. As part of this process when you get to step #3 it will tell you to map a network folder to easily upload your design assets to the Master Pages gallery.

To map my folder I use the normal process of doing such. Something like this –> http://support.microsoft.com/kb/308582

Doing this caused an error on my basic Windows 2008 R2 server.

Error – Windows cannot access http://<SITE&gt;

Error Code: 0×80070043

The network name cannot be found.

image

How to Fix

Add the feature ‘Desktop Experience’ to your server

By going to server manager and adding this feature, upon reboot I was able to successfully map the network drive to my SharePoint 2013 master pages gallery

image

Theme Builder Lives On!

For those working with SharePoint 2010 themes this tools seemed to be amazing at giving me those .THMX files. Until they took it away, but they never told me it would come back as something else.

If you go to http://connect.microsoft.com/ThemeBuilder and sign in with you window live id you’ll notice a nice error message

image

Theme Builder has been reincarnated and I just found it yesterday. I’ve always kept a copy of the original Theme Builder anyway. But now here it is

Open XML Theme Builder

My favorite XSL tips / tricks

I’m compiling a list of my favorite XSL tip and tricks that always help me. These items are not going to be in any particular order

1) Linking Javascript or CSS

<xsl:text disable-output-escaping="yes">
<![CDATA[ 
 <link rel="stylesheet" href="/Style Library/myCss.css"/>
 <script type="text/javascript" src="/Style Library/js/myScript.js"></script>
]]>
</xsl:text>

2) Stripping HTML 

the first section is the how to call the template below it

<!-- calling template -->
<xsl:call-template name="remove-html">

 <xsl:with-param name="text" select="@MyText">
</xsl:call-template>
<!-- template -->
<xsl:template name="remove-html">
    <xsl:param name="text"/>
    <xsl:choose>
        <xsl:when test="contains($text, '&lt;')">
            <xsl:value-of select="normalize-space(substring-before($text, '&lt;'))"/>
            <xsl:text> </xsl:text>
            <xsl:call-template name="remove-html">
                <xsl:with-param name="text" select="normalize-space(substring-after($text, '&gt;'))"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="normalize-space($text)"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

3) Trim String

<xsl:choose>
  <xsl:when test="string-length(@MyString) > 50">
    <xsl:value-of select="substring(@MyString, 1, 49)" />...
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="@MyString" />
  </xsl:otherwise>
</xsl:choose>

4) Show all XML output

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<xmp><xsl:copy-of select="*"/></xmp>
</xsl:template>
</xsl:stylesheet>

5) SharePoint Templates

A nice set of pre-built .xsl templates for use which contains some helpful things.

SharePoint XSL Templates

 

SharePoint CSSRegistration or Link?

I must say that I’ve been using <link> for my style sheets for some times now. Until recently have seen the benefits from using the CSSRegstration method and now using that exclusively from now on. Even in my master page where I know the CSS files will only load once I will use it. I was unaware that CSSRegistration had Conditional Expression built in to target other browsers, but now that I know that I have no excuse not to use it.

Using the After property

Most of the time you’ll want to load your CSS file after the core V4 css gets loaded. To do this you’ll use the property After=”corev4″.css”

2012-05-01_2043

You’ll see in image below that the files are appearing after the corev4.css file which is the main SharePoint styling CSS file.

2012-05-01_2201

Removing the After property you’ll see the style0.css applied before the corve4.css and style1.css applied after it.

2012-05-01_2212

2012-05-01_2213

Order of Loading

Take notice to the order that you are setting them in the master page. The style sheets set first in the master page will be applied last on page load.

2012-05-01_2043

When the page loads you can see the output.

Style1.css , then Style0.css

2012-05-01_2046

Using Conditional CSS

The CSSRegstration class has properties to target specific browsers similar to this method. http://www.quirksmode.org/css/condcom.html

2012-05-01_2256

Which renders like this, where the comments will target different browsers.

2012-05-01_2257

You don’t have to enter the IF in the condition, that is done for you. But to access NON IE browsers you’ll have to specify another property to reach downlevel clients. Pay special attention to the ConditionalExpression which is set to !IE, to reach other browsers you need to also specify the RevealToNonIE=”True”

2012-05-01_2356

Doing so will prepare that conditional CSS comments in a way that Firefox, Chrome or other Non-IE browsers can read them.

2012-05-01_2358

Controlling Multiple Loading

On benefit of using the SharePoint:CSSRegistration tag is to handle the issue of loading a CSS file multiple times. As CSS files grow bigger and bigger it can be a problem with page load times if you are loading multiple web parts and using the link tag

By using the regular <link> tag to reference your CSS files each time that gets hit it will load your css to the page.

Using CSS Registration will not do that. take this example below. I’m attempting to register the Style1.css, 2 additional times, and style0.css 1 additional time

2012-05-02_0006

and the output will only load the css files once

2012-05-02_0008

Specifying Current Site Collection Urls

Another benefit of using the SharePoint:CSSRegistration tag is the ability to specify files that live in the Style Library in a Site Collection not located at the root of the domain. What do I mean by that? Consider that we are building a branding solution and we are storing the files in the Style Library of that site collection and say for example that the domain is test.contoso.com

So deploying our solution to test.contoso.com would put the files in at test.contoso.com/Style Library/mycss.css. Now when we register the CSS files using the <link> tag it would look like this

2012-05-02_0024

Say you have sub site collections under another managed path that link would break. For example, consider another site collection called /Sites/SC1. This would be test.contoso.com/sites/sc1 and the masterpage would try to find the file at test.contoso.com/Style Library using that <link> tag above.

That would NORMALLY not be a problem if the branding solution or files were deployed to the site collection at “/” and then at “/sites/sc1”. BUT if you only deploy the branding to the “/site/sc1” site collection the files would only exist in that Style Library for that site collection. So the links to the css would be looking at test.contoso.com/Style Library/mycss.css and be broken because the files are NOT there and the files are at test.contoso.com/sites/sc1/Style Library/SC1.

So as confusing as that may have sounded there is an answer to handle that situation.

1. You deploy CSS and images to the Layouts folder – This makes the files available globally. Any reference to CSS or images should start with  /_layouts/MyDeploymentFolder/myCss.css

2. Use SPUrl to handle the adjustment of the link to the appropriate site collection.

Examining #2 – SPUrl

By using the $SPUrl:~SiteCollection you can specify a parameter which will return the current site collection. Below I’ve embedded into a master page

2012-05-02_2313

This is the result on my root site collection “/”

2012-05-02_2319_001

This is the result on another site collection under a managed path “/sites/sc1”

2012-05-02_2319

So as you can see, using this method you can deploy your css / images to the Style Library and be able to access them using this current site collection url parameter.

This about wraps up the major aspects of using CSSRegistration over Link. To sum up the main benefits we have:

Achieved with Link or CSS Registration

  • Controlling load order
  • Conditional CSS
  • Specify site collection relative style sheets

Achieved with CSS Registration only

  • Preventing loading the same file multiple times