Chapter 9. Programming and caching for performance – SharePoint 2010 Web Parts in Action

Chapter 9. Programming and caching for performance

 

This chapter covers

 

Performance is crucial! When you’re using SharePoint’s cool functionality to develop Web Parts, user controls, or other SharePoint artifacts, you’ll likely build applications that consume server, client, and bandwidth resources. While in development mode, your Web Parts will run fine, but once they’re in production, with more data and more users, your applications can degrade in performance. Personally, I’m a performance fanatic and like to achieve even the smallest optimization.

You can choose among several methods for improving performance. SharePoint is quite fragile and can be a performance killer if it’s not programmed and handled correctly. You must know how to handle the SharePoint objects and know how to query correctly to get good performance. Several techniques can be used to improve the performance of the server-side executed code.

Caching is the next step to take once you’ve optimized your code. Caching allows the server to temporarily store already calculated or executed operations, thereby delivering them much faster to the client. SharePoint offers a number of configuration options to help you enhance performance.

9.1. Programming for performance

When thinking about performance, most developers consider how to optimize loops or reduce the number of local variables. Although such actions can improve performance, if the compiler doesn’t already make those improvements, you need to look at the bigger picture. People have different opinions as to what performance is. Here are a few of the common aspects:

It can be hard to maximize the performance in all these areas. Depending on the type of application, the focus may shift between these aspects.

9.1.1. Computational performance

Computational performance is all about how fast code and algorithms are performed. Improving computational performance entails selecting the correct algorithms for your calculations and knowing how the application is designed in terms of classes, objects, and layers. The Developer Dashboard, used with the scoped monitors, is a great source for measuring computational performance.

9.1.2. Object and memory usage

Optimizing the object and memory usage might sound simple in managed code, but it’s easy to fail at this task when working with SharePoint. The SharePoint objects such as SPSite and SPWeb contain references to COM+ objects, and each of these objects consumes quite a lot of memory. Later in this chapter, I’ll show you how to handle these objects in a correct and safe way.

Following a design pattern and using a layered architecture will most likely result in many classes that will increase the memory footprint. To improve performance you might have to bend the rules to keep the number of objects down. On the other hand, bending the rules can also lead to code that’s hard to understand and consequently more difficult to troubleshoot.

9.1.3. Scalability

Scalability is an application’s ability to perform well under heavy loads or when processing a large amount of data. An application that performs well with just a few users may degrade in performance when stressed by many requests. The same goes with data; the application might perform well with small sets of data but perform poorly handling large amounts. A common mistake is failing to test the application thoroughly using relevant data and expected amounts of data. In the development and testing phases, you may use small numbers of users and small sets of data. But when running the application in production, the data and usage grows and performance degrades. A well-designed application is easier to scale out or up. Chapter 13 discusses design patterns that also are testable.

9.1.4. Perceived performance

In the Web Part world, perception may be the most important aspect of performance. It’s about how the end users experience the performance of the application. SharePoint 2010 has improved perceived performance by using more Ajax-based functionality such as the dialog framework. Making long-running calls such as web requests may stall other Web Parts. This problem can be solved by making the Web Part asynchronous on the server side and the client. This metric is hard to measure and depends on many factors, such as the overall SharePoint performance, client browser, and client caching.

Perceived performance is also about testing. You need to test your solutions several times under different conditions using production data and realistic loads. It’s not fun when the users or customers complain that their solution runs slowly and you know you didn’t test it thoroughly.

9.2. Programming for performance in SharePoint

Building applications for SharePoint requires that you have a thorough understanding of the SharePoint objects and how they work. All the SharePoint data is stored in the content databases, so most of the commands use a database connection and query the database. These operations are larger than optimizing a for loop. Not handling these SharePoint objects can jeopardize the stability and performance of the SharePoint farm.

SharePoint 2010 introduces new techniques for querying data such as LINQ to SharePoint. Although such techniques might improve the development experience, they’re not always the way to go when programming for performance. On the other hand, because LINQ to SharePoint uses the new CAML features that allow for relational queries, you can, in some situations, create a single query that targets multiple lists instead of having multiple queries. There are various ways to query SharePoint and each has its pros and cons.

Your Web Part might retrieve data from an external system that takes time to deliver a response or needs to wait on other processes to finish. This can cause your application to block execution for other Web Parts and thus slow down the response for the whole page. You can use asynchronous operations so that your Web Part isn’t responsible for killing the performance of a page or a site.

Not all performance improvements are implemented in your server-side code. You should also seriously consider optimizing your JavaScripts, CSS files, and other resources.

9.2.1. Proper handling of SharePoint objects

If you’ve been working with SharePoint or participated in any SharePoint classes, you’ve probably heard that you must dispose the SharePoint objects such as SPSite and SPWeb. It’s a common beginner’s mistake not to dispose. Forgetting to dispose these objects might affect the stability of the whole server. The objects need to be disposed because they have references to the COM+ object, which won’t be released automatically by the garbage collector. The COM+ objects contain connections to the SharePoint databases, and if not released, the server will unexpectedly recycle the application pool, or even worse, eventually run out of connections and refuse SharePoint access to the databases. The following snippet shows a correct handling of the disposable SPSite object:

SPSite site;
try {
    site = new SPSite("http://server");
    // ...
}
finally {
    site.Dispose(); }

Inside the try block, the SPSite object is created and used. The finally block is always executed, even if an exception occurs, and the object will always be disposed. These statements can be shortened with the using statement, which will do exactly the same thing:

using (SPSite site = new SPSite("http://server")) {
    // ...
}

The using statement will implicitly create try-finally blocks and correctly dispose the objects created in the using statement. All SPSite and SPWeb objects that are created by you must be disposed.

Instances of SPSite and SPWeb created by SharePoint—for instance, from the SPContext object—must not be disposed. They’re shared by all Web Parts and controls in the current request and disposing these objects will dispose the current context and eventually cause exceptions in other Web Parts using the context. Reducing the number of SPSite and SPWeb objects allows for better scalability and a smaller memory footprint.

 

Tip

Microsoft has released a tool called the SharePoint Dispose Checker Tool, also known as SPDisposeChecker, which checks your compiled assemblies for problems related to failing to dispose the SharePoint objects and gives you an indication of common mistakes. You can include the tool in your Visual Studio postbuild scripts or add it to a code analysis rule set. You can download the tool here: http://code.msdn.microsoft.com/SPDisposeCheck. Use SPDisposeChecker with caution because it may report false positives.

 

9.2.2. Make smarter queries to SharePoint

Many Web Parts you’ll build will query SharePoint for information from lists or sites. There are several ways to query SharePoint for information. The query will have different performance implications, depending on how it’s done and which method you use. Creating the correct query is especially important when working with large lists. Next, I’ll show you how to query a standard Tasks list for all items that have the status set to Completed.

Querying Using the Object Model

The easiest (but worst performing) way to query a SharePoint list is to iterate over the objects and check the fields for the data via the SharePoint object model. The following code snippet shows how to iterate over the Tasks list items using a foreach statement:

SPWeb web = SPContext.Current.Web;
SPList tasks = web.Lists["Tasks"];
foreach (SPListItem task in tasks.Items) {
    if (task["Status"].ToString() == "Completed") {
        Label1.Text += task.Title;
    }
}

The Tasks list is retrieved from the current SPWeb object before iterating over all items. To get the correct items, a string comparison is done on the Status field.

For a very small list, this code works fine, but as the list grows, this method will perform poorly. First, when iterating over the items in the list, the complete list item objects are retrieved from the database and read into memory. Second, the fields aren’t strongly typed, which means you must programmatically convert the fields into the correct type. Doing this will also make your code more error prone.

Querying Using LINQ to SharePoint

SharePoint 2010 introduces a tool called SPMetal that can generate strongly typed objects of your lists and list items. The code generated by this tool allows you to use LINQ to query the SharePoint objects. You can more easily write queries and you don’t have to be concerned with converting types.

 

Note

SPMetal is a tool that generates entity classes to provide an object-oriented way to work with the objects within a SharePoint site. The tool is available in SharePoint Foundation and is located in {SharePoint Root}\BIN (it’s called SPMetal.exe).

 

The following code snippet shows how the previous object model listing is uses the entity classes generated by SPMetal and LINQ queries:

using (SPMetalDataContext context = new SPMetalDataContext(
    SPContext.Current.Web.Url)) {

    var tasks = from task in context.GetList<TasksTask>("Tasks")
                where task.TaskStatus == TaskStatus.Completed
                select task.Title;
    foreach (var title in tasks) {
        Label1.Text += title;
    }
}

To use the entity classes, you need a data context, which you create using the URL to current web site. A LINQ query is performed using the Tasks list, where all completed tasks are sorted out. Finally, all titles of these tasks are returned.

Using the entity classes (created by SPMetal) and LINQ, you can perform the query using strongly typed properties. This approach reduces the number of errors in the code. Behind the scenes, the LINQ query is converted to a CAML (Collaboration Application Markup Language) query that queries the database and returns only the items that match the query. This reduces the number of items in memory for this Web Part, and the query is faster than manually iterating the items. If the list contains a large number of items, this method is far better than the previous. To further improve performance, consider using the LINQ Take(n) method to return only the number of items that you really need.

The downside to using LINQ to SharePoint is that it requires that the LINQ runtime be loaded, which makes the first call slower compared to the succeeding ones. It also requires that more objects and classes be loaded into memory. If you’re working with anonymous users, such as public-facing websites, you should know that LINQ to SharePoint doesn’t currently support anonymous users in the RTM version. Cumulative updates for SharePoint have resolved this and it will work in upcoming service packs.

Manually Creating CAML Queries

The best way to query lists is to create the CAML queries manually—that is, create the same CAML that’s created under the hood by the LINQ to SharePoint classes. CAML can be hard to learn at first, but in high-performance scenarios learning CAML can be worth the time. Visual Studio lacks good tools and support for building CAML queries, so it’s easier to make mistakes than if you use the LINQ to SharePoint method.

 

Tip

The SharePoint DataContext object used in LINQ to SharePoint contains a property called Log. You can set this property to any TextWriter object such as the Console.Out or the return value from the File.Create Text method. All queries executed in the DataContext will then be written to the TextWriter as CAML. You can use this logged CAML in your manual CAML queries.

 

The following code snippet demonstrates how to create the same query as earlier using a manual CAML query:

A CAML query is created by using an SPQuery object and then setting the Query property to the CAML query to be used . The query object is used to return the items from the list .

This approach is faster than the previous ones. But it’s likely to take longer to develop the query, and you’ll find that the opportunities to introduce errors into the code are greater than when you’re using the LINQ to SharePoint approach. An alternative to SPQuery is the SPSiteDataQuery, which allows for cross-site queries.

9.2.3. Asynchronous operations

Using asynchronous operations to read data isn’t often done in web applications (compared to client applications). That’s because web applications are request-response based and the server-side execution has to wait for the asynchronous operation to complete before it delivers the response. This is true as long as there’s one asynchronous operation going on at the same time. For example, think of the RSS Web Part from previous chapters; it’s requesting the RSS feed from another server and waiting for that response. This operation can sometimes take a second or two. If there’s one instance of the Web Part on the page, there’s not much you can do about it. But what if there are several instances of the RSS Web Part (which is common in SharePoint where the end users build their own pages)? If the request for the RSS feeds is run synchronously, then the time to deliver the request will increase and consequently slow down the page, even though the server isn’t doing any calculations.

A better approach is to run each request for the RSS feed asynchronously, which means that the requests will be executed in parallel. Then the time for rendering the page will be almost equal to the time of the longest-running RSS feed request.

To illustrate how to run operations asynchronously, let’s modify our RSS Web Part. ASP.NET contains a method called RegisterAsyncTask for registering asynchronous tasks with the pages. This method registers a PageAsyncTask object that contains information about the task to be executed asynchronously. The registered asynchronous tasks are automatically called and synchronized after the PreRenderComplete event. To add the asynchronous functions to the RSS Web Part, add a new class called RSSFeedAsyncTask to our Web Part item, as shown in listing 9.1. This new class is responsible for handling the asynchronous events.

Listing 9.1. Asynchronous task for fetching an RSS feed

The class that handles the asynchronous task contains an asynchronous task delegate and a delegate to use once the task is done. This custom class has a constructor that takes the URL of the feed and a reference to the delegate method to use when the task is ended. Once the task is registered and ASP.NET decides to start executing the action, it will call the OnBegin method . This method creates the asynchronous delegate for the Execute method that contains the code for requesting the feed and then starts the asynchronous call of the delegate. When the asynchronous call is done, the OnEnd method is called. This method invokes the AsyncTaskEnded delegate passed to the constructor before ending the asynchronous call. In case of timeouts, the class has a method called OnTimeout, which is called if the operation takes too long (the default is 45 seconds). The actual method that fetches the RSS stream is the Execute method, which makes the call just as in the synchronous version of the Web Part . When testing and debugging the Web Part, consider inserting a sleep statement here so that you can see that it performs the actions in parallel. The property FeedData is used to set and retrieve the XML from the RSS feed.

What’s left is to edit the control creation in the Web Part class. Listing 9.2 shows how the CreateChildControls method is altered and registers an asynchronous page task.

Listing 9.2. An asynchronous Web Part that fetches an RSS feed

The previously shown asynchronous task, in listing 9.1, is defined as a private variable. The method that’s changed is CreateChildControls. Instead of directly requesting the feed, an asynchronous object is created with the URL and the name of the method to run when the task is completed. A PageAsyncTask object is created with references to OnBegin, OnEnd, and OnTimeout methods, and this object is passed to the RegisterAsyncTask method of the ASP.NET page object. ASP.NET will then invoke all registered asynchronous tasks after the PreRenderComplete page event. The execution will continue without directly requesting the RSS feed, and you set up a Panel object to be used for adding the feed items. When the asynchronous task is finished, it will call the feedFetched method that was passed into the custom asynchronous task class constructor. This method checks that it contains data and then retrieves the RSS feed XML from the FeedData property. The control tree is built in the same way as it was in the CreateChildControls method of the synchronous Web Part, except that you now add the feed items to the BulletedList object in a separate method.

This technique is great to use when you have operations that can take a long time or that block other Web Parts from running. In this example, a web request was the bottleneck, but the issue can be other types of resources such as database calls, long-running calculations, or even synchronization with other Web Parts or controls.

You can register multiple asynchronous operations in your Web Part—for example, if you need to combine two RSS feeds into one and execute those requests in parallel. By default, ASP.NET executes all registered tasks after the PreRenderComplete, but you can also manually execute all the current registered tasks by calling the ExecuteRegisteredAsyncTasks method on the Page object. Note that this will synchronize all asynchronous tasks within the current scope or Web Part and will block other Web Parts from running until the task is complete. Also note that these asynchronous operations aren’t available in sandboxed solutions.

These asynchronous operations were done on the server side. To improve the perceived performance, consider using asynchronous client-side operations using Ajax, which I’ll discuss in the next chapter.

9.2.4. Improve performance of resources

Most likely your application will contain images, CSS files, JavaScript, and other resources that the clients will download. Downloading a lot of content not only affects bandwidth, it also reduces the performance of the web page rendering. By taking a look at all these resources, you can improve the overall performance of your SharePoint solution.

You can optimize JavaScript and CSS files by reducing whitespaces and redundant characters. You can find several tools available on the internet to help you with this. Optimizing your files will reduce the bandwidth used and the time needed to download the item.

 

Tip

Microsoft has released a JavaScript tool that minifies and optimizes your JavaScript files, called Microsoft Ajax Minifier 4. You can download it at http://aspnet.codeplex.com/releases/view/40584.

 

Another simple thing to do is to reduce the number of files. You can merge JavaScript and CSS files so that you have only one or just a few of each. For images it’s a bit trickier but it can be accomplished in combination with CSS sprites. CSS sprites are CSS rules pointing out a specific area of a larger image. Instead of having multiple images, merge all your images into a composite image. Figure 9.1 shows how two images can be combined into one single image. The big benefit of this isn’t the size of the resources but rather that it reduces the number of requests to the server. SharePoint extensively uses this approach for all images used in the Ribbon menu.

Figure 9.1. Using composite images instead of multiple images in combination with CSS sprites can improve the application performance and reduce the server load.

You can use CSS sprites to display only one of the images from the combined image. Do so by creating an HTML element or ASP.NET control that uses the image as a background image and then use CSS to specify the background position. Figure 9.2 shows a Web Part with a LinkButton control that uses a CSS sprite image using the left image in figure 9.1. When a user hovers the mouse over the LinkButton control, the image will be switched to the right image in figure 9.1 without loading a new image or changing the actual image used.

Figure 9.2. Using CSS sprites that show a specific part of a composite image in Web Parts will reduce the load on the servers and improve the performance of SharePoint. When you hover the mouse over the image in the figure, the image will change—not by loading a new image but by shifting the focus on the sprite image to show another part of it.

To create the LinkButton using the CSS sprite, you first need to combine the images and add the resulting image into the project. Then create a style declaration with the necessary CSS classes either directly in a Visual Web Part or preferably in a CSS file:

This snippet contains three CSS selectors. The first is a CSS class that defines the size of the control, which is the size of the icons in the image. Because a LinkButton creates an A tag, you also need to make it into a block element. The second class contains the default layout of the link button with a background image . The background image is positioned so that only the left icon is shown. The last CSS class is used when the mouse cursor is positioned over the link using this class, and it uses the same image but another positioning.

To use these CSS classes, create a LinkButton control in your Web Part. This control should have the CssClass property set to linkButton:

<asp:LinkButton
    ID="linkButton"
    runat="server"
    CssClass="linkButton"
    Text=""/>

The CSS classes ensure that the correct image is used when users hover the mouse over the link button.

Improving performance of the application isn’t all about coding smart—you need to look at the whole picture. When you’re optimizing the resources of Web Parts tools such as Fiddler can be of great use. You can use such a tool to see the size of downloaded resources and the timeline when they’re downloaded.

9.3. Caching techniques

One popular and effective technique for improving performance is caching. Caching means that data or objects are transparently saved so that future requests can be served faster. You can do this on the server side by storing already calculated answers or query results in the memory, or the web browser, so that the browser doesn’t have to download the object again. Caching also means that users might not always see the latest information. If you require real-time data, caching may not be an effective option. Web Parts using long-running tasks or CPU-intensive operations may benefit from using caching.

ASP.NET provides several mechanisms for caching objects and data. SharePoint, which is built on top of ASP.NET, also has a set of methods for improving performance by using caching. The SharePoint caches are normally managed by SharePoint administrators and don’t involve any programming tasks. It’s a good practice to use caching and you should, as a developer, be aware of the different caching methods and techniques. Implementing caching in Web Parts may significantly improve performance for scenarios when you have time- or CPU-consuming operations. But doing so requires careful planning.

Instead of implementing caching in your Web Part, you can use the SharePoint built-in caches such as the BLOB cache and save you and your client development time. As a last resort, you can enable caching in Internet Information Services (IIS). IIS allows you to configure both server-side and client-side caching.

9.3.1. ASP.NET caching

Building custom cache mechanisms for multithreaded applications is hard work and something I don’t recommend you do. Fortunately, ASP.NET provides a cache that has all the functionality you need. It’s an in-memory cache that stores data in the memory of the local server and web application. This means that if you have multiple servers or web applications in your farm, the caches and possibly the information on the pages may be different for different users.

The ASP.NET Cache

The ASP.NET cache, which is defined in the System.Web.Caching.Cache class, stores cache data, in memory, using a key value and an object value. You add an object to the cache by specifying the name and the data:

HttpRuntime.Cache.Insert("key", data);

 

Note

you’re using the HttpRuntime.Cache object instead of HttpContext.Cache. HttpContext.Cache requires that you run the code in the context of a web request whereas you can use HttpRuntime.Cache in any .NET application, including unit tests.

 

This code will insert the data object into the cache with the key value of key. The object will reside in the cache until removed or the application pool is recycled. Most often a cache is used to temporarily store objects and invalidate the cached value at specific times or when dependencies change. The ASP.NET Cache object offers functionality for adding time spans when the cache item should be invalidated and for connecting dependencies for invalidation. To insert a cache item that should live for 20 seconds, you have to specify a few more parameters as follows:

HttpRuntime.Cache.Insert(
    "key",
    data,
    null,
    DateTime.Now.AddSeconds(20),
    TimeSpan.Zero);

This code will add the item with a key and a value into the cache. The third parameter, which specifies any cache dependencies, isn’t used here. The fourth parameter specifies the time when the cache is invalidated, which is the current time plus 20 seconds. The last parameter is used for sliding expiration and in this case it’s set to 0. Sliding expiration means that the cache item will remain in the cache for at least that time span after the item was last accessed.

Cache dependencies are specific logical dependencies between items in the cache and the originating source item. For instance, data stored in a cache may be calculated from values in a file in the file system. When the file is changed, the cache item that’s dependent on this file should be removed from the cache. ASP.NET contains cache dependencies for files, other items in the cache, SQL tables, or rows. You can even create your own cache dependencies by inheriting from the CacheDependency class defined in System.Web.Caching. To make a cache item dependent on a file, you must create a CacheDependency object and then insert the object into the cache like this:

CacheDependency dependency = new CacheDependency(fileName);
HttpRuntime.Cache.Insert("key", "value", dependency);

To access items in the cache, use the Get method of the Cache object. This method returns the item as an object (or null if the item isn’t found in the cache):

object cacheItem = HttpRuntime.Cache.Get("key");

Objects will automatically be removed from the cache once its policies expire or any dependencies change. To remove items manually from the cache, you can use the Remove method with the cache item key as a parameter:

HttpRuntime.Cache.Remove("key");
ASP.NET Partial Caching

The ASP.NET runtime also contains functionality for partial caching. Partial caching means that you can cache single-user controls or a whole Web Part for a single page or for all pages. The partial caching is enabled on user controls declaratively in the user control using the OutputCache control directive or in the code-behind using the PartialCaching attribute. They both take a number of arguments that specify the cache duration and when to cache the control. To make a Visual Web Part cache its output for a minute, add the following directive to the top of the user control:

<%@ OutputCache Duration="60" VaryByParam="none"%>

This will make the Visual Web Part cached for 60 seconds for all pages where this Web Part is used. If you’ve previously worked with ASP.NET sites and used caching, you’ll notice that this isn’t how it works in ASP.NET. In plain ASP.NET sites with partially cached user controls, the item is cached per page, not all pages at once as in SharePoint. Keep this in mind: SharePoint caching is controlled by SharePoint on an application level and ASP.NET controls caching at the page or control level. Nevertheless, it can be useful for Web Parts that have static content that doesn’t need to be updated often. Another pitfall with using partial caching is that it isn’t cached per user; it’s only cached once for all users. So you should never use partial caching in Web Parts if you’re using the current user’s credentials or information to render the content or when you’re using personalization.

The parameters to the OutputCache directive can be used to control the cache, though. You can set the VaryByParam parameter to a custom value corresponding to the name of a query string parameter or forms parameter. This will make the control cache differently, depending on the value of the parameter. For example, the following code will result in different cached controls if the value of the query string parameter, country, is changed and the control depends on the value of the query string parameter:

<%@ OutputCache Duration="60" VaryByParam="country"%>

The VaryByParam can contain several parameters separated by commas if the control is dependent on several parameters.

If you need to cache the contents of controls, you should rely on the SharePoint Server 2010 Output Cache. This is a cache for full and partial caching of pages and controls when using the Publishing Infrastructure. This output cache is built on top of the ASP.NET caching mechanism and is enhanced with customizable caching profiles configurable through the web interface.

 

Tip

You can read more about output caching in SharePoint Server 2010 here: http://msdn.microsoft.com/library/aa661294.aspx.

 

9.3.2. Caching objects and structures

Caching items such as strings, integers, or other simple data types is easy to do with the ASP.NET cache. Once the cache item is invalidated, the item is removed from the cache—and eventually from memory by the garbage collector in .NET. But what about objects such as SPSite or SPWeb or other SharePoint objects that require manual disposal—can those objects be cached in the ASP.NET cache? The answer is no. You should never cache objects that require disposal, that have references to unmanaged code, or that aren’t thread safe. Instead, create a custom thread-safe cache object and put it into the cache.

To demonstrate how to create a custom cacheable object, let’s build a Web Part that shows statistics for all lists in a website. This Web Part will display a table containing all lists with the title, description, and the current number of items, as shown in figure 9.3. It will also be configurable with a custom property so that the caching can be turned on or off. You’ll also use monitored scopes so that you can measure the difference in time using the Developer Dashboard for the noncached and cached Web Part.

Figure 9.3. Building Web Parts that read data from SharePoint can be resource intensive; if possible, they should use caching to improve performance.

First, create a custom class that you’ll use to store the list information in the cache. You can’t add the SPList object to the cache because it’s not thread safe. Your custom class should look like this:

class CacheData {
    public string Title;
    public string Description;
    public int ItemCount;
}

The class contains three public properties that are used to store the data that’s going to be shown in the Web Part. Because the Web Part will display all lists in the site, a generic list object of the type List<Cachedata> will be the actual object stored in the cache.

The Web Part contains a configurable property called UseCaching that’s used to determine whether the caching is enabled. The property definition is implemented like this:

[WebBrowsable(true)]
[Personalizable]
[WebDisplayName("Use cache")]
public bool UseCaching {
    get;
    set;
}

The statistics Web Part creates a table, iterates through all the lists, and adds a row for each one with its properties. It’s all generated in CreateChildControls, as you can see in listing 9.3.

Listing 9.3. Web Part that displays all lists in a site and the number of items in each list

The Web Part creates the table and adds the necessary headings before checking whether the caching is enabled . If caching isn’t enabled, the Web Part iterates over all lists in the current website and produces the output.

If caching is enabled, the Web Part should regenerate the table using cached values of the list properties. Listing 9.4 shows how the caching is implemented.

Listing 9.4. Implementation of caching for the list statistics Web Part

When caching is enabled, the Web Part will try to get the data from the cache using the specific cache key. If it doesn’t find anything , the Web Part will create a new object to add to the cache—in this case, a List<T> of the CacheData object defined earlier. The Web Part will iterate over all lists in the current site, create a new Cache Data object for each list, and add values to it . This object is then added to the list. When all objects are added to the list, the Web Part will insert the object into the cache . Finally it creates the table using the newly created list or using the data fetched from the cache .

Because you added monitored scopes to the Web Part, it’s easy to compare the performance of the noncached and cached mode using the Developer Dashboard. When not using the cache, this is what’s shown in the dashboard:

Reading data from SharePoint (14.09 ms)

After enabling the cache and reloading the page, this is what the Developer Dashboard shows:

Reading data from Cache (0.06 ms)

Quite an improvement! Note that this example uses the same static cache key for all users. In a real-world scenario the cache key should be user unique because the lists and their contents might be secured.

Although the HttpRuntime.Cache object is thread safe, your code might require a lock, using the C# lock keyword, if loading the data takes a lot of time. By using a lock, you prevent all incoming requests from loading the same data and causing excessive load on the server. If you use a lock, only the first incoming request loads the data and the subsequent requests wait for the loading to complete (for the lock to release) and then use the cached state, which the first request created.

9.3.3. Caching resources

For high-availability sites, it’s necessary to cache JavaScript, Silverlight applications, CSS files, and images. These types of content are static and can benefit a lot from caching. For these resources, there are two types of caching:

  • Client-side caching—Resources are cached on the client.
  • Server-side and BLOB caching—The server caches items so that they aren’t generated or fetched from the databases.
  • These two types of caching can be used together for optimal performance.
Client-Side IIS Caching

In client-side caching, the web server tells the web browser that it can cache the requested item locally for a specific duration. The next request by the client for a page containing these resources won’t require that the client request the cached resources.

Allowing the browser to cache the resources can improve the performance of your application and reduce the load on your servers. By default SharePoint enables content expiration in IIS for the _LAYOUTS, _WPRESOURCES, and CONTROLTEMPLATES folders. The default setting is 365 days. This means that when the browser requests information from these folders, it will cache the items in the local cache for 365 days or until the cache is cleared. Most browsers do send a request to the server for cached objects to see if it’s been updated. If the object hasn’t changed, the server will send an HTTP 304 response that tells the browser that it can use the object from the local cache. Note that this content expiration isn’t set for the WPRESOURCES folder, which is used for web application scoped resources.

In addition, the content expiration isn’t set on any items or content existing in the SharePoint content databases. To enable caching on these resources, you have to use the BLOB cache in SharePoint Server 2010, which I’ll discuss in a moment.

Not only browsers take advantage of the client-side caching; other network performance enhancers such as WAN accelerators make use of it. Client-side caching can improve the performance of geo distributed installations.

 

Tip

Another approach to improve the performance of applications is to use a content delivery network (CDN). A CDN is a service network that hosts resources instead of you having them on your network. These services are high performing and often geo distributed, and they take load off your network and servers. Microsoft has a CDN that hosts the ASP.NET Ajax and jQuery JavaScripts, which you can read more about here: http://www.asp.net/ajaxlibrary/cdn.ashx.

 

Server-Side IIS Caching

You configure server-side caching in IIS by navigating to the site and path that you want to cache items in using IIS Manager. Then select the Output Caching feature in the Features View and click Add in the Actions menu to the right. A dialog box will open, as shown in figure 9.4. Here you specify the cache rules for the selected path.

Figure 9.4. You can configure caching of files in IIS 7.0 using the Output Cache feature. This rule will cache all PNG files for one hour for a site using anonymous authentication.

Enter the filename extension for the files that you’d like to cache and then select a mode to use for caching. In the File Cache Monitoring section, choose the cache duration and then click OK to save the rule.

The major difference between Kernel mode and User mode is that in User mode the cache resides in the IIS worker process and in Kernel mode the cache resides in the kernel driver HTTP.SYS. Kernel mode can’t be used on sites that require authentication or authorization, because those IIS features are User mode features.

Server-Side BLOB Caching

In SharePoint a lot of content is stored in the content databases. To reduce the database load so that SharePoint queries the database for all requests to files that can be considered static, such as CSS files and images, you should configure SharePoint for caching. SharePoint Server 2010 contains a special cache called the BLOB cache, which caches the items on the file system instead. This functionality isn’t available in SharePoint Foundation 2010.

The BLOB cache isn’t enabled by default and requires that you make changes to the web.config file of the web application. The configuration of the cache is in the element called BlobCache. Here’s the default configuration of the BLOB cache:

<BlobCache
    location="C:\BlobCache\14"
    path="\.(gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv)$"
    maxSize="10"
    enabled="false" />

The BLOB cache caches the items in the file system and the path is specified using the location attribute. I strongly recommend that you store the BLOB cache on a separate disk for optimal performance. The path attribute specifies a regular expression that contains the extensions of the files to cache. The BLOB cache will store up to maxSize gigabytes (GB) of data in the cache. To enable the BLOB cache for the web application, set the enabled attribute to true.

By default the BLOB cache only caches the items on the server to reduce database load. If you’d like to enable caching of these objects on the client side, you need to add the max-age attribute. This attribute contains a numeric value that represents the number of seconds that the item should be cached on the client side.

The BLOB cache is probably the most efficient and easy way to enable caching of content in your SharePoint site and you should consider using it in all your projects. Remember that the setting is per web application.

9.4. Summary

Now that you’ve finished this chapter, I hope you’ll enjoy performance optimizations as much as I do. You’ve seen that you have several options for improving the performance of your Web Parts, ranging from simple rules for handling and working with SharePoint to building your own caching. You need to take a look at the big picture and focus on the expensive parts first. Building custom caching can be hard work but worth it in the end. Whenever you’re using expensive resources such as database connections, web requests, and services, consider caching the result. Just make sure that you don’t forget the security aspects when caching. And as I stated earlier, use the built-in caching mechanisms when appropriate in SharePoint and keep it simple.