Leveraging .net 4.5 to Increase the Performance of Telligent Community

We've been working with Telligent Community (Telligent Community) since the product was first launched as Community Server version 1.  The product started as a lightweight combination of 3 applications combined into a basic platform and has evolved into an Enterprise platform that is used by some of the biggest brands in the world. Over this time we moved from .net 1 to to .net 4.5 and indeed versions of IIS have changed.  The way the internet is presented has changed, pages are now much richer and contain more functionality, consequently the amount of page data and external files has increased.

Telligent Community is no exception to this rule and generally each page request has anything between 40 and 100 or more individual requests back.  All of this backwards and forwards to the server adds a significant latency to the complete download of the page and is extremely visible on slow connections, additionally downloading individual CSS files and Javascript files is inefficient for the browser and causes the rendering engine to suffer.

Occasionally my technical abilities are allowed to be used in the company, not often enough I say! On this occasion I was learning more about the semantic web and how it is changing SEO and page rankings, there will be a post on this at a later date.  For now suffice to say by researching and creating a plugin for the semantic web I started thinking about how we could improve the performance in Telligent Community . One of the techniques that sprang to mind was bundling, this is now aLeveraging .net 4.5 to Increase the Performance of Zimbra Community native feature of .net 4.5. Bundling is the process of aggregating and minification of files to reduce the amount of data being sent to the browser and also reduce the number of requests to IIS.

My starting point for figuring out how to bundle files was to think about how Telligent Community renders the page.  Telligent Community uses the standard aspx pipeline to render it's pages and then internally there are constructs that build the page based on layouts and widgets.  Every page has a set of javascript and css includes defined by the theme and then additional javascript and css files defined by each widget. 

The first problem I had to address in-order to build my bundle was deciding how to intercept the rendering of the page.  There is no simple way to hook into Telligent Community when rendering the widgets or the master pages, which meant that being able to process the javascript and css includes as the controls were being rendered was not an option.  Fortunately for my semantic web project I already had the solution in the form of CsQuery. CSQuery allows a developer in C# to parse HTML and then use jQuery style selectors to navigate and modify the markup. The alternative choice was to use Regular Expressions, however the performance overhead of multiple regular expression queries would be higher than a single parse of CsQuery. 

The next hurdle was to get to the page as it was rendered and then perform the required processing.  The solution came in the form of the Microsoft Reactive Extensions and a new feature of .net 4.5.  Using PreApplicationStartMethod I was able to register a new module wrapped in a plugin.  This plugin's responsibility is to hook into the rendering pipeline using a response filter to parse the document into CsQuery and then using Ms-RX to notify observers that a page is ready to be formatted.  In order to speed up performance we used an updated version of the memory stream class that allocated fix memory blocks rather than using the standard MemoryStream class.

 Now that I had a mechanism to read the page and update the markup I had to figure out how to update and identify which elements could be bundled.  The Microsoft bundling code allows you to bundle files using 2 base classes ScriptBundle and StyleBundle.  In a typical deployment these are populated and registered up front, unfortunately due to the dynamic nature of Telligent Community this is not possible, so I created a set of wrappers that understand how to parse the HTML to extract the links that can be bundled and also update the HTML to reference the bundle URL.

The StandardStyleBundle class is pretty simple, it extracts meta links that reference CSS in the page adds them to the bundle.  Depending on the type of link it will use a particular bundle file handler.  In the case of CFS and remote files these are copied to a local cache on the server.  This prevents servers from getting out of sync with page layouts when in a web farm.

The StandardScriptBundle does the same as the StandardStyleBundle class, however it additionally handles web resource (axd) links and also widget files by enumerating over the widgets on the page to identify widget scripts.

The class diagram above describes the solution in a little more detail.

The important part of this project is the metrics and this is where it gets quite interesting because there is an obvious cost in performing the parsing of the mark up. We did spend a fair amount of time making sure the code was as performant as possible, it costs about 15% of the total time of a request on the server which considering what it's doing is pretty quick.  If the current web page response time on your server is 200ms then by adding this code the response time will increase to 230ms.  This is not a good headline from all the effort that has gone in so lets look at some other metrics. On the default Fiji theme the web page will make approximately 45 requests with the performance plugin installed this is reduced to 19 and byte size reduced by about 20%.  That means that IIS is serving 50% less pages, which in theory means that we have made room for more requests to be made, may be not 50% more but a considerable number.  It also means that a client rendering the page suffers from latency 50% less.  However the headline figure that I want to present is the client rendering. Because the javascript and css are downloaded in one block the processing occurs much more quickly in fact the client speed improvement is circa 60% on a typical page.  This makes a massive difference to user perception because the page loads more quickly and cleanly basically the site feels faster.

Here are some screenshots from the 4 roads site before and after:

BEFORE

AFTER

 

We've decided that this plugin and some other future plugins are going to be released for free to all Telligent Community clients, we have versions for Telligent Community 6.0 upwards.  If you would like to try out our plugin then please contact us and we will be happy to send it to you.