Question

I want to delete some of the webparts from my sites when they are created. I've stapled a feature that runs custom code. I've attached the basics of what it does below, edited for brevity.

It works but when you create a my site you get the error message "The operation could not be completed because the Web Part was deleted by another user or is invalid.", I'd guess because it's trying to load the webparts that the background thread is halfway through deleting. Refresh and the page loads fine.

Any ideas how to get around this?

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    thread.Start(deletethestuff)        
}

public override void DeleteTheStuff
{
    while (checksiteisprovisioned == false) Thread.Sleep(1000);

    SPFile page = web.RootFolder.Files["default.aspx"];
    SPLimitedWebPartManager manager = page.GetLimitedWebPartManager(PersonalizationScope.Shared));
    foreach (Microsoft.SharePoint.WebPartPages.WebPart webPart in webParts)
    {
        if (webPart.Title == "onetodelete")
        {
            manager.DeleteWebPart(webPart);
        }
    }
    page.Update();
}
Was it helpful?

Solution

The way i do this is as described in Steve Peschka's blog post on the SharePoint team blog: http://blogs.msdn.com/sharepoint/archive/2007/03/22/customizing-moss-2007-my-sites-within-the-enterprise.aspx

OTHER TIPS

The issue here is that you are modifying the web parts collection at the same time as iterating through it. You need to build a separate collection and then use that for the deletion e.g.:

SPFile page = web.RootFolder.Files["default.aspx"];
SPLimitedWebPartManager wpmShared = page.GetLimitedWebPartManager(PersonalizationScope.Shared);

List<WebPart> partsToProcess = new List<WebPart>();

foreach (WebPart part in wpmShared.WebParts)
{
     if (part.Title == "onetodelete")
     {
         partsToProcess.Add(part);
     }
}

foreach (WebPart webPart in partsToProcess)
{
     wpmShared.DeleteWebPart(webPart);
}     

page.Update();

The way i've always done this is to create another feature that would delete the webparts but not staple it to any sites. Then I would have another feature that is stapled to the sites that would kick off two things:

One, I used threads and it works pretty well but I did it slightly different than you:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    using (SPWeb web = (SPWeb)properties.Feature.Parent)
    {
        if (web == null) throw new ApplicationException("Web could not be found");

        ThreadPool.QueueUserWorkItem(new WaitCallback(RunProcess), web.Url);
    }
}

private void RunProcess(object state)
{
    bool provisioned = false;
    SPWeb web = null;

    try
    {
        for (int i = 0; i < 100 && provisioned == false; i++)
        {
            try
            {
                string url = (string)state;
                using (SPSite site = new SPSite(url))
                {
                    web = site.OpenWeb();
                    if (web.Provisioned)
                    {
                        provisioned = true;
                        break;
                    }

                    if (web != null)
                    {
                        web.Dispose();
                    }

                    Thread.Sleep(3000);
                }
            }
            catch { }
            finally
            {
                if (web != null &&
                    provisioned == false)
                {
                    web.Dispose();
                }
            }
        }

        if (provisioned)
        {
            DoSomething(web);
        }
        else
        {
            throw new ApplicationException("Web site never provisioned");
        }
    }
    finally
    {
        if (web != null)
        {
            web.Dispose();
        }
    }
}

and then in do something I would activate the unstapled feature.

Two. I would add a one time timer job set to run in 5 minutes that would also activate the same feature.

This way 99% of the time the thread would execute correctly, but the 1% that is doesn't, there is a timer job that will take care of it after a little bit of a delay.

I would never go with a background thread like this during the site provisioning, it is just made to fail.

In your case I would create a copy of the MSITE Site definition, without the Web Parts and use that site def for the My Sites instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top