MVC4 - Bundling does not work when optimizations are set to true
Asked Answered
C

6

44

I wonder what I don't do correct here. I am using ASP.NET C# MVC4 and I want to take use of new css/js optimization feature.

Here is my HTML part

@Styles.Render("~/content/css")

Here is my BunduleConfig.cs part

bundles.Add(new StyleBundle("~/content/css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

// BundleTable.EnableOptimizations = true;

Output (works):

<link href="/content/css/reset.css" rel="stylesheet"/>
<link href="/content/css/bla.css" rel="stylesheet"/>

However when I uncomment BundleTable.EnableOptimizations = true; html output looks like this

<link href="/content/css?v=5LoJebKvQJIN-fKjKYCg_ccvmBC_LF91jBasIpwtUcY1" rel="stylesheet"/>

And this is, of course is 404. I have no idea where I did something wrong, please help, first time working with MVC4.

Confutation answered 2/9, 2012 at 22:3 Comment(2)
What happens if you create the ~content/css/reset.min.css and bla.min.css files that EnableOptimizations=true tends to look for?Halpern
I just created empty project and tried with two css files and same thing happened. Maybe it is because I put my css files in /content/css/ folder and not just /content/ however I doubt it...Confutation
C
71

I imagine the problem is you putting the bundle at a virtual URL that actually exists, but is a directory.

MVC is making a virtual file from your bundle and serving it up from the path you specify as the bundle path.

The correct solution for that problem is to use a bundle path that does not directly map to an existing directory, and instead uses a virtual file name (that also does not map to a real file name) inside that directory.

Example:

If your site has a folder named /content/css, make your css bundle as follows:

In BundleConfig.cs:

bundles.Add(new StyleBundle("~/content/css/AllMyCss.css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

And on the page:

@Styles.Render("~/content/css/AllMyCss.css")

Note that this assumes you do NOT have a file named AllMyCss.css in your css folder.

Calendar answered 3/9, 2012 at 0:53 Comment(3)
Won't putting the bundle at a not existent directory cause problems with relative references in the CSS? devwhib.blogspot.com/2012/08/…Swindle
Many ways to solve the relative reference problem. If you have relative references in your css, either convert them to absolute references, embed the resources in the css, treat the relative references as if the css file itself lives at the virtual url, or make the virtual url be the same depth as the actual file location.Calendar
did exactly as you said @Calendar but, still not working :( getting 404 error in browser console for this url: localhost:60676/Content/css/…Niela
P
26

I'm not sure if it's the web optimization, or WebGrease that is so picky but one (or both) of them is and you need to be extremely careful.

First of all there is nothing wrong with your code:

bundles.Add(new StyleBundle("~/content/css").Include(
                        "~/content/css/reset.css",
                        "~/content/css/bla.css"));

In fact this is exactly what Microsoft does. The main reason they don't use ~/bundles for css is that relative paths get screwed up for images. Think about how your browser sees a bundle - exactly the same way as it sees any other URL, and all the normal path related rules still apply with respect to relative paths. Imagine your css had an image path to ../images/bullet.png. If you were using ~/bundles the browser would be looking in a directory above bundles which doesn't actually exist. It will probably end up looking in ~/images where you probably have it in ~/content/images.

I've found a couple things that can really break it and cause 404 errors:

  • FYI: My directory structure is Content/CSS which contains an images folder for CSS images.
  • I have EnableOptimizations=true to force use of bundles while testing
  • First thing you should do is 'View Source' and just click on the css links to see if they work

Let's say we're developing a site about cats. You may have this

 @Styles.Render("~/Content/css/cats.css")    // dont do this - see below why

 bundles.Add(new StyleBundle("~/content/css/cats.css").Include(
                    "~/content/css/reset.css",
                    "~/content/css/bla.css"));

This generates a CSS link to this path in your HTML:

/Content/css/cats.css?v=JMoJspikowDah2auGQBfQAWj1OShXxqAlXxhv_ZFVfQ1

However this will give a 404 because I put an extension .css and IIS (I think) gets confused.

If I change it to this then it works fine:

 @Styles.Render("~/Content/css/cats")

 bundles.Add(new StyleBundle("~/content/css/cats").Include(
                    "~/content/css/reset.css",
                    "~/content/css/bla.css"));

Another problem already pointed out by others is you must not do

 @Styles.Render("~/Content/css")

if you have a css directory or file (unlikely you'd have a file called css with no extension) in your Content directory.

An additional trick is that you need to make sure your generated HTML has a version number

<link href="/Content/css/cats?v=6GDW6wAXIN5DJCxVtIkkxLGpojoP-tBQiKgBTQMSlWw1" rel="stylesheet"/>

If it doesn't and looks like this, then you probably don't have an exact match for the bundle name between your Bundle table and in your cshtml file.

<link href="/Content/css/cats" rel="stylesheet"/>
Perl answered 31/1, 2013 at 22:55 Comment(2)
I'm not sure if I'm misreading here, but it seems like you're suggesting new StyleBundle("~/content/css") is fine and recommended, but also that it isn't fine if you have a css folder in your content directory (which is a pretty standard setup).Pollinosis
@MattMitchell actually that was what the OP said, so I was explaining why it was causing the error and why you shouldn't have it named as such.Perl
T
4

Don't forget to ensure the bundling HttpModule is there.

<modules>  
  <remove name="BundleModule" />  
  <add name="BundleModule" type="System.Web.Optimization.BundleModule" />  
</modules>

This stung me first time around. Not sure if the necessary config should be added by the NuGet package, but it wasn't in my case.

Traditionalism answered 14/1, 2014 at 16:26 Comment(0)
P
3

That looks correct to me. When optimizations are enabled you'll only have a single ref and it'll be for the name you specified in your StyleBundle (/content/css). In debug mode (or more specifically with debug=false in your web config) you'll get the non-optimized files as normal. If you look, you'll see they're just plain text as you typed them. However, when optimzations are turned on (usually when you run in release mode) you'll get a wierd looking URL instead.

If you look at the output of that it'll be minified. The Query string ?v=5KLoJ.... is based on a hash taken of the files in the bundle. This is so that the reference can be safely HTTP cached for as long as you want. Forever if you fancy, but I think the default is a year. However, if you modify any of your stylesheets it will generate a new hash and that's "cache-busting" so you'll get a fresh copy on the browser.

Having said all that, I'm not sure why you're getting a 404. I suspect that has something to do with your routing configuration or your IIS setup. Are you running in Visual Studio with IISExpress?

Paulson answered 2/9, 2012 at 22:18 Comment(2)
I'm running VS2010 using ASP.NET development server (integrated one for testing/debugging).Confutation
Are you calling EnableDefaultBundles()? Otherwise, it sounds like your URLs aren't getting passed through - try changing the mode of your application pool to "integrated".Paulson
Y
3

I just resolved a similar problem. The problem was as follow, i installed 'chosen' via NuGet. And in the BundleConfig class, the line that included the CSS file looked like this:

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css",)); 
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/chosen.css"));

Some where down in that class i had this line:

BundleTable.EnableOptimizations = true;

The fix was to combine the 2 bundles.Add() like so:

bundles.Add(new StyleBundle("~/Content/css").Include(
                            "~/Content/site.css", 
                            "~/Content/chosen.css"
                        ));

And that fixed it for me.

Yasukoyataghan answered 26/5, 2013 at 10:48 Comment(0)
P
0

It also could be because you have not deployed bundleconfig.json to the server for some reason.

Psychiatrist answered 3/12, 2017 at 22:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.