Avoiding UserProfile.PersonalSite Leaks

Roger Lamb has posted another edge case in the pursuit of leak-free object model code: UserProfile.PersonalSite. To help follow his best practices, I offer another round of extension methods. First, for UserProfile:

public static void ProcessPersonalSite(this UserProfile profile, Action<SPSite> action)
{
    using (SPSite site = profile.PersonalSite)
    {
        action(site);
    }
}

public static T SelectFromPersonalSite<T>(this UserProfile profile, Func<SPSite, T> selector)
{
    using (SPSite site = profile.PersonalSite)
    {
        return selector(site);
    }
}

Usage:

void PersonalSiteNoLeak()
{
    // open a site collection
    using (SPSite siteCollection = new SPSite("http://moss"))
    {
        UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
        UserProfile profile = profileManager.GetUserProfile("domain\\username");
        profile.ProcessPersonalSite(personalSite =>
        {
            // Process personalSite
        });
    }
}

int CountContextPersonalSiteWebs()
{
    UserProfile myProfile = ProfileLoader.GetProfileLoader().GetUserProfile();
    return myProfile.SelectFromPersonalSite(personalSite =>
    {
        return personalSite.AllWebs.Count;
    });
}

I’ve also encapsulated the verification logic for accessing a MySite web part’s PersonalSite, with variations for projection and with/without exceptions:

public static void ProcessPersonalSite(this WebPart webpart, Action<SPSite> action)
{
    IPersonalPage personalPage = webpart.Page as IPersonalPage;
    if (personalPage == null)
        throw new SPException("Unable to access personal site. Invalid page.");
    if (personalPage.IsProfileError)
        throw new SPException("Unable to access personal site because of a profile error.");

    action(personalPage.PersonalSite);
}

public static T SelectFromPersonalSite<T>(this WebPart webpart, Func<SPSite, T> selector)
{
    IPersonalPage personalPage = webpart.Page as IPersonalPage;
    if (personalPage == null)
        throw new SPException("Unable to access personal site. Invalid page.");
    if (personalPage.IsProfileError)
        throw new SPException("Unable to access personal site because of a profile error.");

    return selector(personalPage.PersonalSite);
}

public static bool TryProcessPersonalSite(this WebPart webpart, Action<SPSite> action)
{
    IPersonalPage personalPage = webpart.Page as IPersonalPage;
    if (personalPage == null || personalPage.IsProfileError)
        return false;

    action(personalPage.PersonalSite);
    return true;
}

public static bool TrySelectFromPersonalSite<T>(this WebPart webpart, Func<SPSite, T> selector, out T value)
{
    value = default(T);
    IPersonalPage personalPage = webpart.Page as IPersonalPage;
    if (personalPage == null || personalPage.IsProfileError)
        return false;

    value = selector(personalPage.PersonalSite);
    return true;
}

Usage:

protected override void CreateChildControls()
{
    base.CreateChildControls();

    this.ProcessPersonalSite(personalSite =>
    {
        // Process personalSite
    });
}

As always, feedback is encouraged.

Advertisement