Does MVC have a built in way to specify a CDN fallback for style sheets? I am trying to set up a fallback for the jQuery Mobile Structure style sheet.
Here is my code in the RegisterBundles
method:
var JQMstyleSheet = new StyleBundle("~/JQMstyle", "http://code.jquery.com/mobile/1.3.1/jquery.mobile.structure-1.3.1.min.css").Include("~/theme/jquery.mobile.structure-1.3.1.css");
JQMstyleSheet.CdnFallbackExpression = "window.jQuery.mobile";
bundles.Add(JQMstyleSheet);
When the page renders it outputs this to the html:
<script>
(window.jQuery.mobile)||document.write('<script src="/JQMstyle"><\/script>');
</script>
When the CDN fails it doesn't dynamically add the style sheet like it does perfectly for my javascript files.
I think the problem is that it is trying to render a script, when it should be a style. Is there a different fallback property other than CdnFallbackExpression
?
UPDATE
The Microsoft docs for System.Web.Optimization.StyleBundle
shows a CdnFallbackExpression
as an available property, however in the description it says "Gets the script extension rendered by the Scripts
helper class..."
http://msdn.microsoft.com/en-us/library/system.web.optimization.stylebundle(v=vs.110).aspx
Is this a bug in the System.Web.Optimization.StyleBundle
? shouldn't that property by referencing the Styles
helper class?
TLDR;
Check out my solution which provides a StyleBundle extension method to solve the problem.
Style Bundle Fallback
Also
Yes there is a bug in the Microsoft ASP.NET Optimization Framework, documented here.
The solution is to modify the CdnFallbackExpression to be a javascript function that both checks for the stylesheet and loads the fallback, thus ignoring the bad script from the Optimization Framework.
There are a couple of tricky parts, especially checking for a stylesheet being loaded when it comes from another domain, like most CDN sources.
I have a solution on GitHub that you can use until the issue is fixed in the framework; however, I'd still watch out for the tricky part of determining when the stylesheet is actually loaded.
Here is my RegisterBundles method and it works perfectly. It automatically falls back to the local scripts and styles if the CDN fails. See if it can help.
using System.Web;
using System.Web.Optimization;
public static void RegisterBundles(BundleCollection bundles)
{
var jQueryCdn = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.0.min.js";
var jQueryUICdn = "https://ajax.aspnetcdn.com/ajax/jquery.ui/1.12.1/jquery-ui.min.js";
var jQueryUICss = "https://ajax.aspnetcdn.com/ajax/jquery.ui/1.12.1/themes/blitzer/jquery-ui.css";
var jQueryValidateCdn = "https://ajax.aspnetcdn.com/ajax/jquery.validate/1.19.0/jquery.validate.min.js";
var jQueryValidateUnobtrusiveCdn = "https://ajax.aspnetcdn.com/ajax/mvc/5.2.3/jquery.validate.unobtrusive.min.js";
var modernizrCdn = "https://ajax.aspnetcdn.com/ajax/modernizr/modernizr-3.5.0.js";
var respondCdn = "https://ajax.aspnetcdn.com/ajax/respond/1.4.2/respond.min.js";
var bootstrapCdn = "https://ajax.aspnetcdn.com/ajax/bootstrap/4.3.1/bootstrap.min.js";
var bootstrapCSSCdn = "https://ajax.aspnetcdn.com/ajax/bootstrap/4.3.1/css/bootstrap.min.css";
bundles.UseCdn = true;
bundles.Add(new ScriptBundle("~/bundles/jquery", jQueryCdn).Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryui", jQueryUICdn).Include(
"~/Scripts/jquery-ui-1.12.1.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval", jQueryValidateCdn).Include(
"~/Scripts/jquery.validate*"));
bundles.Add(new ScriptBundle("~/bundles/jqueryUnobtrusive", jQueryValidateUnobtrusiveCdn));
bundles.Add(new ScriptBundle("~/bundles/modernizr", modernizrCdn).Include(
"~/Scripts/modernizr-*"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap", bootstrapCdn).Include(
"~/Scripts/bootstrap.js"));
bundles.Add(new ScriptBundle("~/bundles/respond", respondCdn).Include(
"~/Scripts/respond.js"));
//Styles
bundles.Add(new StyleBundle("~/Content/bootstrapcss", bootstrapCSSCdn).Include(
"~/Content/bootstrap.css"));
bundles.Add(new StyleBundle("~/Content/jqueryuicss",jQueryUICss).Include(
"~/Scripts/jquery-ui.css"));
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/site.css"));
//set to true before deployment to use CDN files
BundleTable.EnableOptimizations = true;
}