SharePoint provision default WebParts for MySites

5

Category : SharePoint 2010

SharePoint adds a new site collection for every user when their MySite is created. Recently I had a requirement to add a custom WebPart into a zone on the root page when the MySite gets created. I accomplished this requirement with the following:

  • Feature to create the WebPart
  • Feature Receiver to add the WebPart (this feature receiver ran off of the Feature to create the WebPart)
  • Feature Stapler to activate the Feature to create the WebPart when the site collection is created

The Feature to create the Webpart and Feature Stapler were easy (standard SharePoint development). The Feature Receiver to add the WebPart to a zone on the page is where it got a little tricky and is why I felt a blog is necessary.

Steps

  1. Create a new SharePoint 2010 solution in Visual Studio 2010
  2. Right-click on your project and choose to add a WebPart Feature (you can use a regular webpart or a visual webpart).
    1. For purposes of this blog, we will call this “MySiteWebPartFeature”
    2. Make sure this is a “Site” scoped Feature
  3. Right-click on your project and choose to add an Empty Element for your Feature Stapler
    1. For purposes of this blog, we will call this “MySiteFeatureStapler”
    2. Add a FeatureSiteTemplateAssociation to the MySite templates. Please delete the Id in the example below and replace it with the Id of the feature you created in Step 2
      <FeatureSiteTemplateAssociation Id=”9f8085c2-70cb-4ce1-814b-52e3967e5c3e” TemplateName=”SPSMSITEHOST#0″/>
      <FeatureSiteTemplateAssociation Id=”9f8085c2-70cb-4ce1-814b-52e3967e5c3e” TemplateName=”SPSPERS#0″/>
  4. Right-click on your Features and choose “Add Feature”. This is for your Feature Stapler.
    1. For purposes of this blog, we will call this “MySiteFeatureStapler”
    2. Set the Scope of this Feature to “WebApplication”
    3. Make sure the “MysiteFeatureStapler” element is added as an Item in this feature. Also, go back to the MySiteWebPartFeature and make sure the “MysiteFeatureStapler” element is removed from that one.
  5. Right-click on the MySiteWebPartFeature and choose “Add Event Receiver”
  6. Add the following code in the Event Receiver

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(RunProcess), properties);
}

private void RunProcess(object state)
{
    SPFeatureReceiverProperties properties = (SPFeatureReceiverProperties)state;

    using (SPSite site = (SPSite)properties.Feature.Parent)
    {
        bool provisioned = false;
        while (provisioned == false)
        {
            provisioned = site.RootWeb.Provisioned;
            Thread.Sleep(5000);
        };

        AddWebPart(site.RootWeb.Url);
    }
}

private void AddWebPart(string url)
{

    using (SPSite site = new SPSite(url))
    {
        using (SPWeb web = site.OpenWeb())
        {
            try
            {
                SPLimitedWebPartManager wpm = web.GetLimitedWebPartManager("default.aspx", System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);

                bool webpartexists = false;
                foreach (Microsoft.SharePoint.WebPartPages.WebPart webpart in wpm.WebParts)
                {
                    if (webpart.Title == "My Custom WebPart")
                    {
                        webpartexists = true;
                        break;
                    }
                }

                if (!webpartexists)
                {
                    Treasury_MySites.PrivacyStatement.PrivacyStatement privacyStatementWebPart = new Treasury_MySites.PrivacyStatement.PrivacyStatement();
                    privacyStatementWebPart.ChromeType = System.Web.UI.WebControls.WebParts.PartChromeType.None;
                    privacyStatementWebPart.Title = "My Custom WebPart";
                    wpm.AddWebPart(privacyStatementWebPart, "TopZone", 0);
                }
            }
            catch
            {
                //do nothing
            }
        }
    }
}


In the end, the Feature Stapler needs to be activated at your web application level. When a new site is created within that web application the MySiteWebPartFeature will activate. When that feature activates it will add the WebPart to the webpart gallery (because that’s the standard behavior of a SharePoint WebPart feature). In addition it will run the custom Event Receiver code upon Feature Activation.

The magic of this solution is in the Event Receiver itself. It is using a seperate thread to make sure the root web gets provisioned before adding the WebParts to the zones on the page. Why is this important?

  • If you don’t use a separate thread you could hold up the web from getting provisioned and you will just hang
  • If the web is not provisioned there is no page to add the WebParts to

Is there other ways of doing this? At first I thought the WebProvisioner class would accomplish the same thing. But, that only works on sub-webs, not the root. Other than that, I couldn’t think of another way other than custom master pages or custom site definitions. I’d be glad to hear if anyone else knows another way.

Comments (5)

Hi,
I wish have your source code.
Best regards

Great solution! I was using a custom masterpage to accomplish the post-configuration tasks. This is much cleaner.

Thanks for showing me the light :)

Thanks very much! Just what I needed. I add the webpart through an elements.xml, but I needed some code to wait until the site is provisioned (because otherwise you’ll get unknown errors…)

Thanks again!

I need to create a custom Document Library in My Site template in that case the Document Library will be created automatically while every user creates his My Site. How to do it?

Hi

I a trying to deploy a web part in my own feature staple but I am a bit confused. I am following your code but I have no idea what to replace Treasury_MySites with? Where would I find what to replace this with?

Hopefully you reply to this,
Thank You
Tudor