Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

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();
}
share|improve this question
add comment

4 Answers

up vote 1 down vote accepted

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

share|improve this answer
    
bob on. adding a custom control in the masterpage which edits and then refreshes the page worked a charm. –  Anonymous Apr 29 '10 at 10:45
add comment

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.

share|improve this answer
add comment

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();
share|improve this answer
    
i've actually already got that in my code but trimmed it out. sorry it wasn't clear. –  Anonymous Apr 29 '10 at 8:26
    
Then your code should be fine. I'm using this exact pattern myself in the framework Steve Peschka describes in the article on the SharePoint blog (referenced by Anders below). Also, you are running under elevated privileges yep? –  Chris O'Brien - MVP Apr 29 '10 at 8:58
add comment

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.

share|improve this answer
    
I guess I really didn't asnwer it completely. Your issue is definitly what Chris states. But to get around the issue Wickor pointed out, check out my code above. –  Steve Lineberry Apr 28 '10 at 17:33
    
This is the correct way to use threads if you are going to do it, ie use the thread pool. –  Wictor Wilen MCA MCM MVP Apr 28 '10 at 17:48
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.