Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force BundleCollection to flush cached script bundles in MVC4

... or how I learned to stop worrying and just write code against completely undocumented APIs from Microsoft. Is there any actual documentation of the official System.Web.Optimization release? 'cuz I sure can't find any, there's no XML docs, and all the blog posts refer to the RC API which is substantially different. Anyhoo..

I am writing some code to automatically resolve javascript dependencies and am creating bundles on the fly from those dependencies. Everything works great, except if you edit scripts or otherwise make changes that would affect a bundle without restarting the application, the changes won't be reflected. So I added an option to disable caching of the dependencies for use in development.

However, apparently BundleTables caches the URL even if the bundle collection has changed. For example, in my own code when I want to re-create a bundle I do something like this:

// remove an existing bundle BundleTable.Bundles.Remove(BundleTable.Bundles.GetBundleFor(bundleAlias));  // recreate it. var bundle = new ScriptBundle(bundleAlias);  // dependencies is a collection of objects representing scripts,  // this creates a new bundle from that list.   foreach (var item in dependencies) {     bundle.Include(item.Path); }  // add the new bundle to the collection  BundleTable.Bundles.Add(bundle);  // bundleAlias is the same alias used previously to create the bundle, // like "~/mybundle1"   var bundleUrl = BundleTable.Bundles.ResolveBundleUrl(bundleAlias);  // returns something like "/mybundle1?v=hzBkDmqVAC8R_Nme4OYZ5qoq5fLBIhAGguKa28lYLfQ1" 

Whenever I remove & recreate a bundle with the same alias, absolutely nothing happens: the bundleUrl returned from ResolveBundleUrl is the same as before I removed & recreated the bundle. By "the same" I mean that the content hash is unchanged to reflect the new contents of the bundle.

edit... actually, it's much worse than that. The bundle itself is cached somehow outside of the Bundles collection. If I just generate my own random hash to prevent the browser from caching the script, ASP.NET returns the old script. So, apparently, removing a bundle from BundleTable.Bundles does not actually do anything.

I can simply change the alias to get around this problem, and that is OK for development, but I don't like that idea since it means either I have to deprecate aliases after each page load, or have a BundleCollection that grows in size on every page load. If you left this on in a production environment, it would be a disaster.

So it seems that when a script is served, it gets cached independent of the actual BundleTables.Bundles object. So if you re-use a URL, even if you've removed the bundle that it referred to before reusing it, it responds with whatever's in its cache, and altering the Bundles object does not flush the cache -- so only new items (or rather, new items with a different name) would ever be used.

The behavior seems odd... removing something from the collection should remove it from the cache. But it doesn't. There must be a way to flush this cache and have it use the current contents of the BundleCollection instead of what it cached when that bundle was first accessed.

Any idea how I would do this?

There is this ResetAll method which has an unknown purpose but it just breaks things anyway so that isn't it.

like image 217
Jamie Treworgy Avatar asked Sep 07 '12 11:09

Jamie Treworgy


People also ask

How do you override the bundling setting of web config?

Controlling Bundling and Minification To enable bundling and minification, set the debug value to "false". You can override the Web. config setting with the EnableOptimizations property on the BundleTable class.

What is difference between bundling and minification?

Bundling and minification are two techniques you can use in ASP.NET to improve page load performance for your web application. Bundling combines multiple files into a single file. Minification performs a variety of different code optimizations to scripts and CSS, which results in smaller payloads.

What is use of BundleConfig Cs in MVC?

BundleConfig.cs cs file present in a default MVC5 application. This file contains RegisterBundles() method which is being called at Application_Start() event by global. asax. cs file.

How to bundle scripts in MVC?

In an ASP.NET MVC project, the BundleConfig class in the App Start folder can be used to generate style or script bundles. This method has a parameter bundle, which is of the type BundleCollection. At the start of the program, all of the bundles created are added to this bundle parameter.


1 Answers

We hear your pain on documentation, unfortunately this feature is still changing quite fast, and generating documentation has some lag, and can be outdated almost immediately. Rick's blog post is up to date, and I've tried to answer questions here as well to spread current info in the meantime. We are currently in the process of setting up our official codeplex site which will have always current documentation.

Now in regards to your specific issue of how to flush bundles form the cache.

  1. We store the bundled response inside of the ASP.NET cache using a key generated off of the bundle url requested, i.e. Context.Cache["System.Web.Optimization.Bundle:~/bundles/jquery"] we also setup cache dependencies against all of the files and directories that were used to generate this bundle. So if any of the underlying files or directories change, the cache entry will get flushed.

  2. We don't really support live updating of the BundleTable/BundleCollection on a per request basis. The fully supported scenario is that bundles are configured during app start(this is so everything works properly in the web farm scenario, otherwise some bundle requests would end up being 404's if sent to the wrong server). Looking at your code example, my guess is that you are trying to modify the bundle collection dynamically on a particular request? Any kind of bundle administration/reconfiguration should be accompanied by an appdomain reset to guarantee everything has been setup correctly.

So avoid modifying your bundle definitions without recycling your app domain. You are free to modify the actual files inside of your bundles, that should automatically be detected and generate new hashcodes for your bundle urls.

like image 82
Hao Kung Avatar answered Sep 28 '22 15:09

Hao Kung