15

Every time I deploy an MVC web application my server has to re-cache all js and css bundles.

Because of this it can take several seconds for the first view to render after deploying.

Is there a way to pre-cache bundles? After all, the files are static at compile time.

Hao Kung
  • 28,040
  • 6
  • 84
  • 93
Mark Rucker
  • 6,952
  • 4
  • 39
  • 65
  • 4
    If I understand how the bundling works, it caches in memory in the application domain. At compile time, there is obviously no application domain, so no place to cache the files to. Are you sure that the bundling is what's taking so long? I can't imagine it taking more than a fraction of a second to read a bunch of static files and dump them into memory at runtime. But restarting the app in general without bundling still does take a few seconds. – Joe Enos Jul 15 '13 at 20:26
  • @JoeEnos Yeah, that's kind of what I thought and had found online. I just wanted a second opinion. Thanks. – Mark Rucker Jul 15 '13 at 20:40
  • Different solution, I wanted to get rid of all warming up costs as much as possible so I made my app_start fire off a background web request to every single route in my `RouteTable`. – Chris Marisic Aug 28 '14 at 15:58

1 Answers1

12

Solution

To fix we replaced the default memory cache with caching that persisted beyond the App Pool life.

To do this we inherited from ScriptBundle and overrode CacheLookup() and UpdateCache().

/// <summary>
/// override cache functionality in ScriptBundle to use 
/// persistent cache instead of HttpContext.Current.Cache
/// </summary>
public class ScriptBundleUsingPersistentCaching : ScriptBundle
{
    public ScriptBundleUsingPersistentCaching(string virtualPath)
        : base(virtualPath)
    { }

    public ScriptBundleUsingPersistentCaching(string virtualPath, string cdnPath)
        : base(virtualPath, cdnPath)
    { }

    public override BundleResponse CacheLookup(BundleContext context)
    {
        //custom cache read
    }

    public override void UpdateCache(BundleContext context, BundleResponse response)
    {
        //custom cache save
    }
}

Complications

The only other wrench worth noting had to do with our persistent caching tool. In order to cache we had to have a serializable object. Unfortunately, BundleResponse is not marked as Serializable.

Our solution was to create a small utility class to deconstruct BundleResponse into its value types. Once we did this we were able to serialize the utility class. Then, when retrieving from the cache, we reconstruct the BundleResponse.

Mark Rucker
  • 6,952
  • 4
  • 39
  • 65
  • 3
    may or may not be relevant but your mentioning of BundleResponse http://msdn.microsoft.com/en-us/magazine/cc188950.aspx discusses how to use a serialization surrogate to bypass that limitation, and here's an example http://stackoverflow.com/a/16121346/37055 – Chris Marisic Aug 28 '14 at 16:16