Safely Process SPSite.AllWebs

Probably the ugliest scenario for properly disposing SPWeb objects is cleaning up when you enumerate SPSite.AllWebs. To simplify that task, I present a pair of LINQ-inspired extension methods:

public static void ForEach(this SPWebCollection webs, Action<SPWeb> action)
{
    foreach (SPWeb web in webs)
    {
        action(web);
        web.Dispose();
    }
}

public static IEnumerable<TResult> Select<TResult>(this SPWebCollection webs, Func<SPWeb, TResult> action)
{
    List<TResult> res = new List<TResult>(webs.Count);
    webs.ForEach(w => res.Add(action(w)));
    return res;
}

public static IEnumerable<TResult> Select<TResult>(this SPWebCollection webs, Func<SPWeb, TResult> selector)
{
    foreach (SPWeb web in webs)
    {
        TResult ret = selector(web);
        web.Dispose();
        yield return ret;
    }
}

Combined with lambda expressions, we can cleanly handle tasks that would ordinarily require more code and explicit disposal. Want a list of your web URLs?

var urls = site.AllWebs.Select(w => { return w.Url; });

How about updating a property on every web?

site.AllWebs.ForEach(w =>
{
    w.Properties["MyProp"] = DateTime.Now.ToString();
    w.Properties.Update();
});

We can even leverage anonymous types:

var props = site.AllWebs.Select(w =>
{
    return new
    {
        w.Title,
        w.Url,
        MyProp = w.Properties["MyProp"]
    };
});

Speaking of LINQ and SharePoint, check out Adam Buenz‘s post on using LINQ’s IEnumerable.Cast<T> with SharePoint collections to get IQueryable support. And while using LINQ for filtering and such may be prettier, resist the urge to skip CAML altogether: there is definitely a performance advantage in filtering your SPListItemCollection with an SPQuery, especially for large lists. I can’t seem to find any hard data on this, so I nominate Waldek Mastykarz to investigate – his analyses of other performance topics were great.

Update 12/10/2008: New, improved Select! Discussed here.

Advertisement

5 Responses to “Safely Process SPSite.AllWebs”

  1. waldekmastykarz Says:

    Great idea! I really like the simplicity of the code to process SPWebCollection. Just like you have noticed, you should always research whether there is a better way for retrieving information than walking through the SPWebCollection. For example getting the title and URL might be done using one of the SiteMapProviders as well. But if you want to get some properties your approach by quickly the way to get it done.

    Bookmarked!

  2. Is it a good idea to use lambda expressions for querying SharePoint data? - Waldek Mastykarz Says:

    […] .NET 3x ships with a number of new features among which lambda expressions: an easy way to write code for querying collections. Because of its ease of use many developers use it for retrieving data from different kind of collections. Just recently I’ve been asked to have a look how well lambda expressions perform while retrieving data from Shar…. […]

  3. Implementing LINQ Where for SharePoint « Solutionizing .NET Says:

    […] my previous post, I suggested a Dispose-safe implementation of SPWebCollection.ForEach(), which Waldek leveraged for […]

  4. Implementing LINQ Select for SPWebCollection « Solutionizing .NET Says:

    […] to suggest that others use yield return, I suppose I should take my own advice. In particular, my original implementation of SPWebCollection.Select can be improved using the same techniques I used for […]

  5. LINQ for SPWebCollection Revisited: AsSafeEnumerable « Solutionizing .NET Says:

    […] for SPWebCollection Revisited: AsSafeEnumerable January 5, 2009 — Keith Dahlby I have previously discussed implementations of some core LINQ extension methods for SPWebCollection, a process […]


Comments are closed.

%d bloggers like this: