C# – Using ASP.NET 4.5 Bundling & a CDN (eg. CloudFront)

amazon-cloudfrontasp.net-4.5bundling-and-minificationc

ASP.NET 4.5 has a great new bundling feature and appears to have some support for use of CDNs. The example given by Microsoft for use of the bundling feature with a CDN is this

public static void RegisterBundles(BundleCollection bundles)
{
  //bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
  //            "~/Scripts/jquery-{version}.js"));

  bundles.UseCdn = true;   //enable CDN support

  //add link to jquery on the CDN
  var jqueryCdnPath = "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";

  bundles.Add(new ScriptBundle("~/bundles/jquery",
            jqueryCdnPath).Include(
            "~/Scripts/jquery-{version}.js"));

  // Code removed for clarity.
} 

Which seems to suggest that you need tell it explicitly the path to your file on the CDN.

The CloudFront CDN (and I presume many others) gives you a subdomain which mirrors your own. When you hit http://uniquesubdomain.cloudfront.net/js/myfile.js?v=1 it serves up http://mydomain.com/js/myfile.js?v=1

This way you can simply prefix all your links with http://uniquesubdomain.cloudfront.net/ and your files are server from CloudFront.

Is the ASP.NET 4.5 bundling feature compatible with this type of CDN? Is there a built-in way to have the bundling feature prefix all its links with your CDN domain?

Eg.

bundles.UseCdn = true;
var myBundle= new ScriptBundle("~/bundles/js", "https://uniquedomain.cloudfront.net/");
myBundle.Include("~/js/file1.js");
myBundle.Include("~/js/file2.js");

would cause

    <script src="https://uniquedomain.cloudfront.net/bundles/js?v=6y-qVPSK3RYOYHfPhOBDd92H4LjEjs-D3Hh2Yml6CXA1"></script>

Best Answer

This functionality is not built-in, but is possible with a couple of small helper methods. Here's what I'm using right now:

public static class Cdn
{
    private const string CdnRoot = "//cloudfrontdomainhere.com";

    private static bool EnableCdn
    {
        get
        {
            bool enableCdn = false;
            bool.TryParse(WebConfigurationManager.AppSettings["EnableCdn"], out enableCdn);
            return enableCdn;
        }
    }

    public static IHtmlString RenderScripts(string bundlePath)
    {
        if (EnableCdn)
        {
            string sourceUrl = CdnRoot + Scripts.Url(bundlePath);
            return new HtmlString(string.Format("<script src=\"{0}\"></script>", sourceUrl));
        }

        return Scripts.Render(bundlePath);
    }

    public static IHtmlString RenderStyles(string bundlePath)
    {
        if (EnableCdn)
        {
            string sourceUrl = CdnRoot + Styles.Url(bundlePath);
            return new HtmlString(string.Format("<link href=\"{0}\" rel=\"stylesheet\" />", sourceUrl));
        }

        return Styles.Render(bundlePath);
    }
}

Note that I have my own configuration setting called EnableCdn in the appSettings section of my config file. When called from a Razor view, this produces the correct ouput, which appends the CDN domain onto the paths.

In your Razor files just do Cdn.RenderScripts("~/pathtoscriptbundle")