Caching SharePoint Data and Objects
Recently, we had came across a requirements where we had to cache SharePoint data and objects are server side. We found very nice article from MSDN and used it accordingly for our requirment. Please note that below article is directly copy from original article.
Caching is one good way to improve system performance. However, you must weigh the benefits of caching against the need for thread safety. Additionally, you should not create certain SharePoint objects within event receivers because this will cause performance problems related to excessive database calls
Caching Data and Objects
Many developers use the Microsoft .NET Framework caching objects (for example, System.Web.Caching.Cache) to help take better advantage of memory and increase overall system performance. But many objects are not “thread safe” and caching those objects can cause applications to fail and unexpected or unrelated user errors.
Caching SharePoint Objects That Are Not Thread Safe
You might try to increase performance and memory usage by caching SPListItemCollection objects that are returned from queries. In general, this is a good practice; however, the SPListItemCollection object contains an embedded SPWeb object that is not thread safe and should not be cached.
For example, assume the SPListItemCollection object is cached in a thread. As other threads try to read this object, the application can fail or behave strangely because the embedded SPWeb object is not thread safe. For more information about the SPWeb object and thread safety, see the Microsoft.SharePoint.SPWeb class.
The guidance in the following section describes how you can prevent multiple threads from attempting to read the same cached object.
Understanding the Potential Pitfalls of Thread Synchronization
You might not be aware that your code is running in a multithreaded environment (by default, Internet Information Services, or IIS, is multithreaded) or how to manage that environment. The following example shows the code some developers use to cache Microsoft.SharePoint.SPListItemCollection objects.
Applying Lock
private static object _lock = new object(); public void CacheData() { SPListItemCollection oListItems; oListItems = (SPListItemCollection)Cache["ListItemCacheName"]; if(oListItems == null) { lock (_lock) { //Ensure that the data was not loaded by a concurrent thread while waiting for lock. oListItems = (SPListItemCollection)Cache[“ListItemCacheName”]; if (oListItems == null) { oListItems = DoQueryToReturnItems(); Cache.Add("ListItemCacheName", oListItems, ..); } } } }
If the cache is already populated, this last example performs as well as the initial implementation. If the cache is not populated and the system is under a light load, acquiring the lock will cause a slight performance penalty. This approach should significantly improve performance when the system is under a heavy load, because the query will be executed only once instead of multiple times, and queries are usually expensive in comparison with the cost of synchronization.
The code in these examples suspends all other threads in a critical section running in IIS, and prevents other threads from accessing the cached object until it is completely built. This addresses the thread synchronization issue; however, the code is still not correct because it is caching an object that is not thread safe.
To address thread safety, you can cache a DataTable object that is created from the SPListItemCollection object. You would modify the previous example as follows so that your code gets the data from the DataTable object.
Good Pratice
private static object _lock = new object(); public void CacheData() { DataTable oDataTable; SPListItemCollection oListItems; lock(_lock) { oDataTable = (DataTable)Cache["ListItemCacheName"]; if(oDataTable == null) { oListItems = DoQueryToReturnItems(); oDataTable = oListItems.GetDataTable(); Cache.Add("ListItemCacheName", oDataTable, ..); } } }
Hope this helps…Happy Coding!!!