CDN Implementation For Legacy ASP.Net Website

The Content Delivery Network (CDN) is a media server where we can host a site's images, CSS, JavaScript, PDF and video files and so on.

What is CDN?

The Content Delivery Network (CDN) is a media server where we can host a site's images, CSS, JavaScript, PDF and video files and so on. There will be two media servers, one for a HTTP request and one for a HTTPS request.

Using a CDN server provides the following advantages:

  1. Cached version of files.
  2. Decrease downloading time as files comes from a different server.
  3. Reduce the network traffic.

Let's understand how to implement the CDN and SSL CDN for all the media and graphic files for a legacy website (non MVC site). Suppose you want to implement the CDN for HTTP and HTTPS request and our media servers are like http://media.domain.com and https://securemedia.domain.com respectively. In a legacy site if you do a manual path update for each media and graphic file then it will be a very tough job and there will be a chance that the CDN and SSL CDN score will not be up to the benchmark.

Scenario 1: Suppose you have the master page in your ASP.NET application.

In your master page you can override the Render method. So the following is the code snippet for it.

  1.         protected override void Render(System.Web.UI.HtmlTextWriter writer)  
  2.         {  
  3.             bool isCdnenabled = true;  
  4.             string cdnhost;  
  5.             if (isCdnenabled)  
  6.             {  
  7.                 if (HttpContext.Current.Request.IsSecureConnection)  
  8.                 {  
  9.                     cdnhost = "https://securemedia.domain.com";  
  10.                 }  
  11.                 else if (HttpContext.Current.Request.Headers["ssl"] != null &&  
  12.                                    HttpContext.Current.Request.Headers["ssl"].ToLower() == "true")  
  13.                 {  
  14.                     cdnhost = "https://securemedia.domain.com";  
  15.                 }  
  16.                 else  
  17.                 {  
  18.                     cdnhost = "http://media.domain.com";  
  19.                 }  
  20.             }  
  21.             else  
  22.             {  
  23.                 cdnhost = "";  
  24.             }  
  25.             /* This is to compress the HTML for a faster rendering */  
  26.             using (HtmlTextWriter htmlwriter = new HtmlTextWriter(new System.IO.StringWriter()))  
  27.             {  
  28.                 base.Render(htmlwriter);  
  29.                 string html = htmlwriter.InnerWriter.ToString();  
  30.                 html=Regex.Replace(html, @"(?<=[^])\t{2,}|(?<=[>])\s{2,}(?=[<])|(?<=[>])\s{2,11}(?=[<])|(?=[\n])\s{2,}"string.Empty);  
  31.                 html=Regex.Replace(html, @"[ \f\r\t\v]?([\n\xFE\xFF/{}[\];,<>*%&|^!~?:=])[\f\r\t\v]?""$1");  
  32.                 html = html.Replace(";\t"";");  
  33.                 html = html.Replace(";\n"";");  
  34.                 html = Regex.Replace(html, @"<title>[^\t\r\n[\]]</title>""");  
  35.                 html = Regex.Replace(html, @"<title></title>""");  
  36.                 string regExPatternForImgTags = @"[ \t]((src)|(href))=(?<o>(""|'))([^""']*)(\<o>)";  
  37.   
  38.                 string output = Regex.Replace(html, regExPatternForImgTags, (match) =>  
  39.                 {  
  40.                 /* extracted by RegExp groups, can be usefull for debug and URL modifications*/  
  41.                     string attr = match.Groups[1].Value;  
  42.                     string quote = match.Groups[4].Value;  
  43.                     string url = match.Groups[5].Value;  
  44.                     string newUrl = url;  
  45.                     /* skip external URLs*/  
  46.                     if (!(newUrl.Contains("http://") || newUrl.Contains("https://")))  
  47.                     {  
  48.                         string urlCheck = NoQuery(url);  
  49.                         /// we are processing only several graphics types  
  50.                         if (urlCheck.EndsWith(".png") ||  
  51.                             urlCheck.EndsWith(".jpg") ||  
  52.                             urlCheck.EndsWith(".gif") ||  
  53.                             urlCheck.EndsWith(".css") ||  
  54.                             urlCheck.EndsWith(".ico") ||  
  55.                         url.EndsWith(".js"))  
  56.                         {  
  57.                             /* if CSS pointing on root image by it relative path*/  
  58.                             if (url.Contains("/"))  
  59.                             {  
  60.                                 newUrl = cdnhost + Regex.Replace(newUrl, @"(\.\./)+""");  
  61.                             }  
  62.                             else  
  63.                             {  
  64.                                 newUrl = cdnhost + newUrl;  
  65.                             }  
  66.   
  67.                             return match.Value.Replace(url, newUrl);  
  68.                         }  
  69.                     }  
  70.   
  71.   
  72.                     return match.Value;  
  73.                 });  
  74.   
  75.                 writer.Write(output.Trim());  
  76.             }  
  77.   
  78.   
  79.         }  
  80. public static string NoQuery(string url)  
  81.         {  
  82.             int index = url.IndexOf("?");  
  83.   
  84.             if (index >= 0)  
  85.                 return url.Substring(0, index);  
  86.   
  87.             return url;  
  88.         } 

Scenario 2: Suppose you don't have the master file in your application. Then you can create a HTTP Module and override the BeginRequest method and use the same code.