In SharePoint 2010, a new class has been introduced to loop through the various containers that can be found in the SharePoint object model (like SPSite, SPWeb, SPList, etc). It’s called the ContentIterator which is a part of the Microsoft.Office.Server.Utilities namespace, by making use of this iterator instead of looping through the objects in a regular ‘for-each’ loop you are ‘safe’ by not stressing out the database. Really? How do you know? Well it states in this on the MSDN page :
Provides an interface to iterate through SharePoint objects (such as sites, lists, and list items) to regulate the amount of data transferred. This is especially important for queries on large lists or Web farms so that the load put on the database is not excessive.
(and they are probably right.. right? ;) So how do we use it then? I’ve broken it down into all the various containers that SharePoint has to offer:
Looping through sites:
SPWebApplication webApplication = SPWebApplication.Lookup(new Uri("http://sp2010"));
ContentIterator contentIterator = new ContentIterator();
contentIterator.ProcessSites(webApplication.Sites,
siteProcessor:
delegate(SPSite _site)
{
using (_site)
{
//do something awesome with the site
}
},
errorCallout: (ContentIterator.SiteProcessorErrorCallout)
delegate(SPSite _site, Exception error)
{
return true;
}
);
Looping through webs:
ContentIterator contentIterator = new ContentIterator();
contentIterator.ProcessSite(site,
webProcessor:
delegate(SPWeb _web)
{
using (_web)
{
//do something awesome with the web
}
},
errorCallout:
delegate(SPWeb _web, Exception error)
{
return true;
}
);
Looping through lists:
ContentIterator contentIterator = new ContentIterator();
contentIterator.ProcessLists(web.Lists,
listProcessor:
delegate(SPList _list)
{
//do something awesome with the list
},
errorCallout:
delegate(SPList _list, Exception error)
{ return true; }
);
Looping through listitems (the most basic way):
ContentIterator contentIterator = new ContentIterator();
contentIterator.ProcessListItems(web.Lists["ListName"],
itemProcessor: delegate(SPListItem item)
{
//do something awesome with the item
},
errorCallout: delegate(SPListItem item, Exception error)
{
return true;
});
Performance
The one thing that struck my mind was.. “If I use this, is the performance better as well?”. To answer that question, I created some fairly simple but ‘heavy’ foreach loops like:
foreach (SPListItem item in web.Lists["Big List"].Items)
{
}
and used the Stopwatch to measure the miliseconds on a list that contained 1000 items. Below is a table that shows how long it took while repeating the loop 19 times for both iterators.
| ContentIterator |
‘vanilla’ Foreach |
| 199 |
95 |
| 108 |
97 |
| 110 |
96 |
| 106 |
98 |
| 115 |
106 |
| 107 |
88 |
| 103 |
90 |
| 105 |
309 |
| 109 |
101 |
| 106 |
143 |
| 109 |
106 |
| 107 |
106 |
| 108 |
101 |
| 118 |
100 |
| 122 |
100 |
| 105 |
89 |
| 107 |
92 |
| 106 |
100 |
| 118 |
102 |
As you can see, the ContentIterator is not faster than the ‘expensive' foreach loop. Yet, the question remains.. when do you use ContentIterator? I think a good use would be to use this in timerjobs to minimize the impact of the servers while iterating through the objects. Otherwise, I still have no suggestions up until now but I will look into it more and more, if you have any idea please let me know ;)