The ultimate approach to storing Sitecore media items in CDN
01 June 2012
Przemek Taront
Frink_Cognifide_2016_HeaderImages_0117

This post concerns Sitecore 6.5.0 (rev. 111230).

No modern high-traffic website can live without support from a content delivery network (CDN). One of the services that all major players offer is storage. It enables you to upload your assets to CDN servers and change asset URLs in HTML markup, so that client browsers pull the content directly from the CDN cloud.
   Sitecore in CDN cloud

source: wikipedia.org & sitecore.net

 Recently, I encountered a problem as to how to integrate a Sitecore application with a CDN. The first part of this task is quite easy. I want only published content to be pushed to the cloud, so I have created a handler and subscribed it to publish:itemProcessed event. The handler checks if the item being published comes from Media Library and if yes it uploads the file to the CDN storage using SFTP protocol (or any other secure flavour of FTP).

The tricky part is to modify markup of public pages and change the URLs of local assets to the ones pointing to files stored in the CDN. None of the solutions I found on the Internet was satisfactory, so I decided to contribute.

Exisitng solutions

The simplest solution is to change Media.MediaLinkPrefix, as has been described in Dedicated image server in Sitecore – part 2. If you enter, let's say http://assets.cognifide.com then for example all occurances of ~/images/logo.png will become http://assets.cognifide.com/images/logo.png. But this link modification happens always, even if the content comes from master database and has not been published, thereby spoiling the authoring experience.

Another solution, described on Sitecore Developer Network and applied by Agency Oasis, is to modify GetMediaUrl() method in MediaProvider class. However, they need to plug in to renderField pipeline as well to handle dynamic links separaetely, which makes their solution less elegant and more complex.

Our solution

Let's merge the two solutions above. We are going to extend MediaProvider class (as in the second solution) and override MediaLinkPrefix property (as in the first solution). This value is later used by both GetMediaUrl() method and ExpandLinks() processor from renderField pipeline. Thus, we can apply our custom logic and check what database the content comes from and not plug in to Sitecore twice.

 And voilà, the code is short and simple:
class OriginStorageMediaProvider : MediaProvider, IHook
{
  public string Database { get; set; }
  public string OriginPrefix { get; set; }

  public void Initialize()
  {
    MediaManager.Provider = this;
  }

  public override string MediaLinkPrefix
  {
    get
    {
      if (OriginPrefix != null && Context.Database != null
          && Context.Database.Name == Database)
      {
        return OriginPrefix;
      }
      return Config.MediaLinkPrefix;
    }
  }
}
So is the configuration:
<hooks>
  <hook type="Cognifide.CDN.OriginStorageMediaProvider, Cognifide.CDN">
    <database>web</database>
    <originPrefix>http://sitecore.level3.cognifide.com/storage/</originPrefix>
  </hook>
</hooks>
I hope you enjoyed my post. I'm sure you have some feedback for me, so please don't hesitate to comment!

Get in touch

Name
Name
*
Company
Company
*
Email
Email
*
I'd like a demo of
*
Notes
Notes