Using Cassette with Sitecore MVC

Cassette is a fantastic bundling and minification solution for those developing in ASP.NET. It automatically sorts, concatenates, minifies, caches and versions all your JavaScript, CoffeeScript, CSS, LESS, Sass and HTML templates. By doing this you end up with web pages that issue fewer HTTP requests and you reduce the size of each of those requests.

I recently ran into an unexpected issue when using Cassette with a Sitecore 6.6 MVC implementation that took long enough to get to the bottom of, that I thought it worth documenting. After installing the Cassette nuget package and make the few changes necessary to configure my stylesheet and script bundles I was very happy with the results. All of my local CSS and JavaScript files had been minified and combined and were now being pulled down from the server with just two HTTP requests. Job done and in no time at all, or so I thought.

Deep investigation

Deep investigation (Photo credit: Stéfan)

All was fine until I fired up the Sitecore Page Editor to work on some of the site content. What greeted me after I logged in was quote literally an empty page. The Chrome Dev Tools confirmed that the page requested had indeed returned a zero byte response. I faired no better when I tried to preview the page in the Sitecore Content Editor, I just got the same story, an empty page. The odd thing was that when I hooked up the Visual Studio debugger I could see that all of my MVC layouts, controllers and renderings were executing just as I expected. When this sort of thing happens I usually fall back to chopping out anything that could be interfering with the response, in this case pipeline handlers and finally modules. Eventually the culprit revealed itself, the CassetteHttpModule was responsible for my empty responses.

After a bit of digging I found that Cassette’s rewriteHtml functionality was causing my problem. By default Cassette will buffer and rewrite page HTML output. This allows partial views to insert <link> tags referencing stylesheets after the <head> tag has been rendered. The rewrite functionality gets invoked as a PostRequestHandlerExecute event handler.

Reflector allowed me to play around with the behaviour of the PlaceholderReplacingResponseFilter class which performs the page output rewriting task. This revealed that the empty page responses were the result of the rewritten output stream not being flushed.

        void WriteUncompressedOutput()
            var output = GetOutputWithPlaceholdersReplaced(bufferStream);
            var outputBytes = outputEncoding.GetBytes(output);
            if (outputBytes.Length > 0)
                outputStream.Write(outputBytes, 0, outputBytes.Length);
                // outputStream.Flush(); This fixes the problem ... :]

Running with a patched version of Cassette that implements this stream flushing approach has seen no side effects or loss of functionality. In due course I’ll submit a pull request back to the Cassette repos on GitHub to see whether the change can get incorporated into the master source code.

If you do not require the rewriting functionality a workaround is available now. Just disable the Cassette HTML rewriting feature, either in the web.config file.

      <section name="cassette" type="Cassette.CassetteConfigurationSection, Cassette" />
   <cassette rewriteHtml="false" />

or configure Cassette via code.

public class CassetteSettingsConfiguration : IConfiguration<CassetteSettings>
   public void Configure(CassetteSettings configurable)
      configurable.IsHtmlRewritingEnabled = false;

Although I now know a little bit more about the internal workings of Cassette than I was planning on I have no hesitation in recommending it as bundling and minification tool. For anyone working with ASP.NET MVC or web forms solutions there are many alternative tools to choose from, but few that offer the configuration options and flexibility that Cassette provides.

Recommended reading:


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s