Scope Issues with the Sitecore Page Editor and IIFE

January 7, 2015

The JavaScript IIFE (Immediately-Invoked Function Expression) pattern is awesome and has many benefits like privately scoping your variables. The basic IIFE looks like this:

(function(){
  /* code */ 
}());

Simply replace /* code /* with your custom JavaScript to enjoy the benefits of an IIFE. JavaScript code in this format will work just fine in the Sitecore Page Editor.

The Problem

However, you often see examples of IIFEs using a format similar to:

(function($){
  /* code */ 
}(jQuery));

Passing jQuery as a parameter to your IIFE will cause issues when running your site in the Sitecore Page Editor. You will get Uncaught TypeError: undefined is not a function errors in the console when you call a method defined in the IIFE.

The reason this causes an issue is because the Sitecore Page Editor injects it's own version of jQuery into the page. When you pass jQuery as a parameter to your IIFE it will scope it to just one version. If your calling code is not using that version of jQuery, the method will be undefined.

Summary

The simplest solution is to remove jQuery as a parameter to your IIFE. This may not be possible in all situations, but should work for the majority of front end Sitecore development.

References

For a more detailed discussion on the pros/cons of IIFE parameters see:

UPS Shipping Rate Web Service Errors Out When SSL3 Is Disabled

November 3, 2014

UPS offers a Shipping Rate Web Service in their Developer Kit that can be setup in .Net to do address verification, rate estimation, and other features. Their provided source code will get you started but does not explicitly use TLS security. With the recent SSL v3 vulnerability, POODLE, UPS and other web services will be disabling SSL v3. If your host has disabled SSL v3, you will receive an unexpected packet format or other error when attempting to use the UPS web service.

To fix this, we have to explicitly use TLS security (at least for .Net v3.5 or less). TLS is the next iteration of SSL after SSL v3 and has wide support among clients and servers. You enable it for the UPS web service call by configuring ServicePointManager (a class in the System.Net namespace) to use TLS security.

Using TLS Security

ServicePointManager handles connections to an internet resource and is used when .Net calls the UPS web service. We explicitly set TLS security for that call by using the following line of code:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

This should execute in your code before the web service call. So if we use the ShipClient.cs example from the UPS Developer Kit, lines 111-112 would become:

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ShipmentResponse shipmentResponse = shpSvc.ProcessShipment(shipmentRequest);

Please Note: this is a global change so all web service calls in the application pool would begin using TLS security. To switch back to the default SecurityProtocol, you can save it in a variable and then reassign it to ServicePointManager after the UPS call was finished.

Windows Azure And Cloud Flare; CNAME Record Not Found

October 31, 2014

If you're configuring a Windows Azure shared websites with CloudFlare DNS, you might encounter the CNAME Record Not Found error when trying to add a custom domain name. This can be especially frustrating because Windows Azure will refuse to add the domain name even if you have the correct CNAME records in CloudFlare and you've waited long enough to rule out DNS propagation times.

I was able to resolve this issue by disabling www traffic through CloudFlare, waiting 15 seconds, adding the custom domain to Windows Azure, and then re-enabling traffic through CloudFlare.

Disabling Traffic Through CloudFlare

Even with the alternate awverify CNAME record I had to dsable traffic through CloudFlare on www. You can do this by:

  1. Log into CloudFlare
  2. Select DNS Settings from the Settings list for the applicable domain
  3. Select the Active icon in the www CNAME row

Adding a Push CDN to Sitecore 6.6

October 8, 2014

There is a setting in Sitecore's configuration that should make adding a push cdn simple.  The Media.MediaLinkPrefix can be used to add a different cdn domain.  Setting the value to "/cdn.domain.com/~/media/" worked for most of our images.  However, any images added into the rich text editor would duplicate the prefix when rendered to a page so we were getting urls like the following:

cdn.domain.com///cdn.domain.com/~/media/...

Not only does this create ugly urls, but it doesn't even use the cdn.

To fix this I took a different approach involving changing the url via the MediaProvider.  There are several good articles on configuring pull cdns that you can find in the references.  This solution borrows from the All Things Sitecore article.

Configuration Changes

First, make sure that the Media.MediaLinkPrefix setting is the default empty string.  If it is different, you'll want to change your prefix values below accordingly.

Next, we have to create a new config file in the /App_Config/Include/ directory.  I named mine, cdn.config, and added the following contents:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<hooks>
			<hook type="CustomLibrary.MediaProvider, CustomLibrary">
			<prefix>//cdn.domain.com/</prefix>
		</hook>
	</hooks>
	<mediaLibrary>
		<mediaPrefixes>
			<prefix value="//cdn.domain.com/~/media"/>
		</mediaPrefixes>
	</mediaLibrary>
	</sitecore>
</configuration>

The mediaPrefix, //cdn.domain.com/~/media, is necessary to prevent the prefix duplication.  Requests will still get routed through the cdn and Sitecore treats it as a valid prefix.

Code Changes

Notice the CustomLibrary.MediaProvider, CustomLibrary type in the configuration above.  CustomLibrary needs to be a dll in your project.  CustomLibrary.MediaProvider needs to be a class in that dll that contains the following code:

using Sitecore.Data.Items;
using Sitecore.Events.Hooks;
using Sitecore.Resources.Media;
namespace CustomLibrary
{
	public class MediaProvider : Sitecore.Resources.Media.MediaProvider, IHook
	{
		public void Initialize()
		{
			MediaManager.Provider = this;
		}
		public override string GetMediaUrl(MediaItem item)
		{
			string mediaUrl = base.GetMediaUrl(item);
			return GetMediaUrl(mediaUrl, item);
		}
		public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
		{
			string mediaUrl = base.GetMediaUrl(item, options);
			return GetMediaUrl(mediaUrl, item);
		}
		/// <summary>
		/// Adds CDN domain
		/// </summary>
		/// <param name="mediaUrl"></param>
		/// <param name="item"></param>
		/// <returns></returns>
		public string GetMediaUrl(string mediaUrl, MediaItem item)
		{
			//verify the domain was set in the config
			if (string.IsNullOrEmpty(Prefix))
				return mediaUrl;
			else if (mediaUrl.Contains(Prefix))
				return mediaUrl;
			else
			{
				mediaUrl = RemoveDomain(mediaUrl);
				//clean the url
				if (mediaUrl.StartsWith("/"))
				mediaUrl = mediaUrl.Substring(1);
				//this happens while indexing unless the proper site is set
				mediaUrl = mediaUrl.Replace("/sitecore/shell/", "");
				mediaUrl = string.Format("{0}{1}", Prefix, mediaUrl);
				return mediaUrl;
			}
		}
		public string RemoveDomain(string url)
		{
			if (url.Contains("https://"))
				return url.Replace("https://" + Sitecore.Context.Site.HostName, "");
			else if (url.StartsWith("//"))
				return url.Substring(2);
			else
				return url.Replace("http://" + Sitecore.Context.Site.HostName, "");
		}
		/// <summary>
		/// Property defined in the config
		/// </summary>
		public string Prefix { get; set; }
	}
}

Summary

By using a custom MediaProvider hook, we can ensure that images added through a rich text editor in Sitecore 6.6 rev 140410 use the correct url when using a cdn.  Also, by keeping the code and configuration separate we make it easy to remove if Sitecore fixes this in a future release.

How to Make it Better

This code uses one push cdn domain on all images in a Sitecore solution because that is all that we needed.  However, you could extend this code to use multiple cdn domains or only apply to certain Sitecore sites.  See the references below for additional options.

References

If you are looking for a pull cdn solution or more background on integrating a cdn into Sitecore, check out the following: