Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prepend CDN url to mvc 4 bundler output

Using the built in MVC4 bundler, how do I prepend my CDN url to the link tags it produces? I've setup Amazon Cloudfront so that it pulls assets from my webserver when first requested. So when I define a bundle like so:

 bundles.Add(new StyleBundle("~/Content/css").Include(
    "~/Content/reset.css",
    "~/Content/960_24_col.css",
    "~/Content/Site.css"
 ));

When deployed, I can reference it thus:

http://[cloundfrontid].cloudfront.net/Content/css?v=muhFMZ4thy_XV3dMI2kPt-8Rljm5PNW0tHeDkvenT0g1

Now I just need to change the links produced by the bundler from being relative to absolute links pointing to my CDN.

  <link href="[INSERT_CDN_URL_HERE]/Content/css?v=muhFMZ4thy_XV3dMI2kPt-8Rljm5PNW0tHeDkvenT0g1" rel="stylesheet"/>

I think it may be possible to rewrite the path using IBundleTransform but I can't find any examples of this.

NOTE: Just to be clear, I know you can specify a CDN link for a bundle, but that only works if the bundle can be replaced by a static link.

like image 789
PeteG Avatar asked Feb 12 '13 17:02

PeteG


2 Answers

I just setup MaxCDN and ran into the same exact issue.

As you know, the bundles.UseCdn property is not ideal because we don't want to have to specify the exact url for the bundle. A CDN like Max CDN is the same exact url, query string and all, except for a different subdomain.

Here is how I ended up solving it.

I created a BundleHelper class that will wrap the render method and then prepend the path with the CDN subdomain.

Here is what the class looks like:

namespace MyDomain.Web.Helpers
{
    public class BundleHelper
    {
        public static string CdnPath = "http://cdn.mydomain.com";

        public static IHtmlString RenderScript(string path)
        {
            var opt = System.Web.Optimization.Scripts.Render(path);
            string htmlString = HttpUtility.HtmlDecode(opt.ToHtmlString());

            if (BundleTable.EnableOptimizations)
            {
                htmlString = htmlString.Replace("<script src=\"/", String.Format("<script src=\"{0}/", CdnPath));
            }

            return new HtmlString(htmlString);
        }

        public static IHtmlString RenderStyle(string path)
        {
            var opt = System.Web.Optimization.Styles.Render(path);
            string htmlString = HttpUtility.HtmlDecode(opt.ToHtmlString());

            if (BundleTable.EnableOptimizations)
            {
                htmlString = htmlString.Replace("<link href=\"/", String.Format("<link href=\"{0}/", CdnPath));
            }

            return new HtmlString(htmlString);
        }
    }
}

Then to use it in the views, I simply do:

@BundleHelper.RenderStyle("~/Content/css")
@BundleHelper.RenderStyle("~/Content/themes/base/css")

@BundleHelper.RenderScript("~/bundles/jquery")
@BundleHelper.RenderScript("~/bundles/jqueryui")

Hope this helps.

like image 146
BigJoe714 Avatar answered Nov 10 '22 21:11

BigJoe714


Please have a look @ Using a CDN search for "Using a CDN"

As said by By Rick Anderson in asp.net/mvc,

The follow code replaces the local jQuery bundle with a CDN jQuery bundle.

    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.
    }

In the code above, jQuery will be requested from the CDN while in release mode and the debug version of jQuery will be fetched locally in debug mode. When using a CDN, you should have a fallback mechanism in case the CDN request fails. The following markup fragment from the end of the layout file shows script added to request jQuery should the CDN fail.

    </footer>

        @Scripts.Render("~/bundles/jquery")

        <script type="text/javascript">
            if (typeof jQuery == 'undefined') {
                var e = document.createElement('script');
                e.src = '@Url.Content("~/Scripts/jquery-1.7.1.js")';
                e.type = 'text/javascript';
                document.getElementsByTagName("head")[0].appendChild(e);

            }
        </script> 

        @RenderSection("scripts", required: false)
    </body>
</html>

In have pasted the section from Asp.net/MVC, in case you find it useful then Cheers to Rick Anderson for his post...

like image 40
Shubh Avatar answered Nov 10 '22 23:11

Shubh