Technology

Kentico Multiple CDN Integration

News

It is a well-known fact that modern browsers support around 6 connections per domain at once. Therefore, the first step towards improving the website performance from the client side is to serve assets from additional sub domains (at least 6). This allows the end-users' browsers to send more requests in parallel. These sub domains will make so called static Content Delivery Networks (CDN).

In Kentico such CDN support can be implemented by Output Filter. There are two options of subscribing to a OnAfterFiltering event in Kentico.

Option 1

Create a partial class for CMSModuleLoader and inherit it from CMSLoaderAttribute standard class.

The partial class must be declared without any namespace:

[OutputFilterEvents] public partial class CMSModuleLoader {     public class OutputFilterEventsAttribute : CMSLoaderAttribute     {         public override void Init()         {             // Assigns custom handlers to the appropriate events             ResponseOutputFilter.OnFilterCreated += OutputFilter_OnFilterCreated;         }          private void OutputFilter_OnFilterCreated(ResponseOutputFilter filter)         {             filter.OnAfterFiltering += filter_OnAfterFiltering;         }          static void filter_OnAfterFiltering(ResponseOutputFilter filter, ref string finalHtml)         {             // Place your code here         }     } } 

Next step is to assign a corresponding CDN-domain for the asset URLs. This can be achieved by applying the following regular expression to the initial asset URL:

private static void filter_OnAfterFiltering(ResponseOutputFilter filter, ref string finalHtml) {     const string pattern = "(?url\\(|[\\'\\\"])(?\\/getmedia\\/)(?.+)(?[\\)\\'\\\"])";     var regex = new Regex(pattern);     finalHtml = regex.Replace(finalHtml, ReplaceUrl); } 

Then we have to create the method ReplaceUrl that examines each match and returns either the original matched string or a modified one, as per the defined rules.

private static string ReplaceUrl(Match match) {     if (!match.Success) return match.Value;      var prefix = match.Groups["prefix"].Value;     var handler = match.Groups["handler"].Value;     var asset = match.Groups["asset"].Value;     var postfix = match.Groups["postfix"].Value;     var domain = GetDomain(asset);      return string.Format("{0}{1}{2}{3}{4}", prefix, domain, handler, asset, postfix); } 

In order to keep the CDN domain consistent for the same asset - you must generate it based on the media URL hash as follows:

public static string GetDomain(string mediaUrl) {     var hash = Math.Abs(mediaUrl.GetHashCode());     var index = hash % CdnDomains.Count;     return CdnDomains[index].TrimEnd('/'); } 

As a nice to have feature you can then introduce a CDN configuration to the Kentico interface to control CDN domains:

A list of CDN domains can be built as follows:

private static List _cdnDomains;  private static List CdnDomains {     get { return _cdnDomains ?? (_cdnDomains = BuildCdnDomainList()); } }  private static List BuildCdnDomainList() {     var result = new List();      var domainCount = SiteConfiguration.CDNDomainCount;     var namePattern = SiteConfiguration.CDNDomainNamePattern;     var scheme = SiteConfiguration.CDNDomainScheme;      for (var i = 1; i <= domainCount; i++)     {         var domainName = string.Format(namePattern, scheme, i);         result.Add(domainName);     }      return result; } 
Option 2

Register in Global.asax.

In order to subscribe to OnAfterFiltering event in global.asax you need to do add an event handler to global CMS application events:

  1. Subscribe to OnFilterCreated event;
  2. Subscribe to OnAfterFiltering event.

The recommended code example is below:

public class Global : CMSHttpApplication {     public Global()     {         ApplicationEvents.PreInitialized.Execute += EnsureDynamicModules;         ApplicationEvents.PostStart.Execute += PostStartOnExecute;         . . .     }      private void PostStartOnExecute(object sender, EventArgs e)     {         var eventHandler = EventHandlerHelper.GetStaticEventHandler(typeof(ResponseOutputFilter), "OnFilterCreated");         if (eventHandler == null)         {                 ResponseOutputFilter.OnFilterCreated += ResponseOutputFilter_OnFilterCreated;         }     }      private void ResponseOutputFilter_OnFilterCreated(ResponseOutputFilter filter)     {         var eventHandler = EventHandlerHelper.GetInstanceEventHandler(filter, "OnAfterFiltering");         if (eventHandler == null)             {             filter.OnAfterFiltering += filter_OnAfterFiltering;         }     }       // Place your other methods here . . . } 
CDN URL processing

In order to process the CDN links for assets you have to create a dedicated website in IIS. Point it to the same home directory as your Kentico website and then add all the defined CDN domains as bindings:

Note that you have to add these CDN domains as aliases for your Kentico site and also generate an individual Kentico license for each CDN domain.

To avoid processing requests that aren’t related to obtaining assets by the newly created website for asset - it is essential to create the following redirect rule:

 <rule name="CDN media" enabled="true" stopProcessing="true">     <match url="^getmedia/.*$" negate="true" />     <conditions logicalGrouping="MatchAll" trackAllCaptures="false">         <add input="{HTTP_HOST}" pattern="cdn\d{1}\.your-website\.com" />     </conditions>     <action type="AbortRequest" /> </rule> 

That is all, now with CDN support your website will load much faster.

GET IN TOUCH
Make enquiry

Delete Limited.

Registered in England.

03933385

Registered Address.

3370 Century Way, Thorpe Park, Leeds, LS15 8ZB

VAT Registration.

GB 927 1409 27