Monday, June 6, 2011

Add every installed web part to a single SharePoint page

Here is a code snippet that won't be used for normal day usage, but something is very helpful for testing web part UI and branding. This could also be used for performance benchmarking and exploring or demonstrating different web parts in a development environment. By default, the code will alphabetize the web parts by title and then adds them to the top web part zone.You can easily update the code to filter out specific web parts, update web part properties, populate specific web part zones.

InstructionsThe first thing you’ll want to do is increase the maximum web parts per zone. The default is set to 50, but you can increase it by editing your web.config.
<WebPartLimits MaxZoneParts="100" PropertySize="1048576" />
You can then create a C# Console Application in Visual Studio, add a reference to Microsoft.SharePoint, and then add the following code to Program.cs. This will work with SharePoint 2007 and 2010 as long as you reference the correct assembly. Don’t forget to make sure your Visual Studio project’s Platform Target is Any CPU or x64.
Updated 6/7/2010
  • Better exception handling.
  • Option to delete existing web parts before adding.
  • Link to Web Part Page Maintenance.
Notes:
The Web Analytics Web Part and Date Filter web parts can be added manually, but have bugs that won’t allow them to be added programmatically. See comments in source code. The Excel Web Access web part is also the only one that did not have a Web Part Title by default. This is why I ended up using the Web Parts gallery list title instead. Hopefully these will be addressed with an later update.
One other thing I noticed is that sometimes the code will not add all web parts. This usually happens when I have run the code too many times in a row and my guess is a timer job is getting caught up or something is being cached. If you are on a slower environment, you may want to consider adding a few sleep statements between each web part added.
As far as results are concerned, when I create a site collection using the Publishing Portal site template and enable every site collection and site feature, I see 75 web parts total. Other than the Web Analytics and Date Filter web parts, I have seen everything else successfully added to the page.
Screenshots
Console Application – Note: I did find errors with the Web Analytics and Date Filter web parts
image
SharePoint Page – Notice how large that vertical scrollbar is. Winking smile
image
Keep in mind that you can easily delete any web parts, by going to the Web Part Page Maintenance page. Simply append the query string ?contents=1 to the page URL.
image
Source Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;

namespace AddAllWebParts
{
    class Program
    {
        static void Main(string[] args)
        {
            AddAllWebParts("http://spdev/sites/publishingportal/SitePages/Home.aspx", true);
        }

        public static void AddAllWebParts(string pageUrl, bool deleteExisting)
        {
            int wpInstalledTotal = 0;
            int wpTotal = 0;
            string webPartTag = "<WebPartPages:WebPartZone";
            try
            {
                using (SPSite site = new SPSite(pageUrl))
                {
                    using (SPWeb web = site.OpenWeb())
                    {
                        using (SPLimitedWebPartManager wpMgr =
                            web.GetLimitedWebPartManager(pageUrl, PersonalizationScope.Shared))
                        {
                            if (deleteExisting)
                            {
                                try
                                {
                                    List<System.Web.UI.WebControls.WebParts.WebPart> pageWps = 
                                        new List<System.Web.UI.WebControls.WebParts.WebPart>();
                                    foreach (System.Web.UI.WebControls.WebParts.WebPart wp in wpMgr.WebParts)
                                    {
                                        pageWps.Add(wp);
                                    }
                                    foreach (System.Web.UI.WebControls.WebParts.WebPart wp in pageWps)
                                    {
                                        Console.WriteLine(string.Format("Deleting Web Part: {0}", wp.Title));
                                        wpMgr.DeleteWebPart(wp);
                                        web.Update();
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Console.WriteLine("Error Deleting Existing Web Parts" + ex.Message);
                                }
                            }
                            web.GetCatalog(SPListTemplateType.WebPartCatalog);
                            SPList wpList = web.GetCatalog(SPListTemplateType.WebPartCatalog);
                            SPFile file = web.GetFile(pageUrl);
                            string zoneId = string.Empty;
                            string sourceCode = System.Text.Encoding.UTF8.GetString(file.OpenBinary());
                            if (sourceCode.IndexOf(webPartTag) > -1)
                            {
                                zoneId = sourceCode.Substring(sourceCode.IndexOf(webPartTag));
                                if (zoneId.IndexOf("ID=") > -1)
                                {
                                    zoneId = zoneId.Substring(zoneId.IndexOf("ID=")).Replace("ID=\"", "");
                                    zoneId = zoneId.Substring(0, zoneId.IndexOf("\""));
                                }
                            }
                            if (!string.IsNullOrEmpty(zoneId))
                            {
                                List<SPListItem> wpItems = new List<SPListItem>();
                                wpTotal = wpList.Items.Count;
                                foreach (SPListItem item in wpList.Items)
                                {
                                    wpItems.Add(item);
                                }
                                wpItems.Sort((x1, x2) => x1.Title.CompareTo(x2.Title));
                                wpItems.Reverse();
                                foreach (SPListItem item in wpItems)
                                {
                                    try
                                    {
                                        string fileName = string.Format("{0}/{1}", item.Web.Url, item.File.Url);
                                        XmlTextReader reader = 
                                            new XmlTextReader(new StringReader(item.Web.GetFileAsString(fileName)));
                                        string error;
                                        System.Web.UI.WebControls.WebParts.WebPart wp = wpMgr.ImportWebPart(reader, out error);
                                        if (string.IsNullOrEmpty(error))
                                        {
                                            Console.WriteLine(string.Format("Adding Web Part: {0}", item.Title));
                                            switch (item.Title)
                                            {
                                                case "Date Filter":
                                                    //TODO: Date Filter has a TargetInvocationException. Not sure why this fails.
                                                    break;
                                                case "Web Analytics Web Part":
                                                    //TODO: Web Analytics Web Part fails with an XML. 
                                                    //I have validated the dwp and even removed comments to no avail.
                                                    //http://social.technet.microsoft.com/Forums/en-CA/sharepoint2010programming/thread/f2f7684d-58a7-4fb4-94a4-199ba4132a53
                                                    break;
                                            }
                                            wpMgr.AddWebPart(wp, zoneId, Convert.ToInt32(0));
                                            wpMgr.SaveChanges(wp);
                                            web.Update();
                                            wpInstalledTotal++;
                                        }
                                        else
                                        {
                                            Console.WriteLine(string.Format("Error Adding Web Part: {0} {1})", item.Title, error));
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        Console.WriteLine(string.Format("Error Adding Web Part: {0} {1})",
                                            item.Title, ex.Message));
                                    }
                                }
                                Console.WriteLine("Adding Content Editor Web Part with Web Part Page Maintenance Link");
                                ContentEditorWebPart contentEditor = new ContentEditorWebPart();
                                contentEditor.ZoneID = zoneId;
                                contentEditor.ChromeType = PartChromeType.None;
                                XmlDocument xmlDoc = new XmlDocument();
                                XmlElement xmlElement = xmlDoc.CreateElement("p");
                                xmlElement.InnerText = "<h3><a href='" + pageUrl + "?contents=1'>Web Part Page Maintenance</a></h3>";
                                contentEditor.Content = xmlElement;
                                contentEditor.Content.InnerText = xmlElement.InnerText;
                                wpMgr.AddWebPart(contentEditor, contentEditor.ZoneID, 0);
                                wpMgr.SaveChanges(contentEditor);
                                web.Update();
                            }
                            else
                            {
                                Console.WriteLine("The page contains no web part zones.");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            Console.WriteLine(string.Format("Total Web Parts Added: {0} of {1}", wpInstalledTotal.ToString(), wpTotal.ToString()));
            Console.Read();
        }
    }
}

4 comments:

  1. Very nice information shared by you. I was just searching this type of information and luckily I got it from your blog. I like your blog also. Keep it up.

    ReplyDelete
  2. This should be useful enough to have it inside my system.

    ReplyDelete
  3. Lengthy but very gud information from your side :)

    ReplyDelete
  4. apparently DateFilterWebPart cannot be added without a context. you can fake a context and it will work

    #fake context - the SPWeb object passed to the SetContextWeb method must be created using the SPSite.OpenWeb() method
    $site = New-Object Microsoft.SharePoint.SPSite($webUrl)
    $web = $site.OpenWeb()
    [System.Web.HttpRequest] $request = New-Object System.Web.HttpRequest("", $web.Url, "")
    $sw = New-Object System.IO.StringWriter
    $hr = New-Object System.Web.HttpResponse($sw)
    [System.Web.HttpContext]::Current = New-Object System.Web.HttpContext($request, $hr)
    [Microsoft.SharePoint.WebControls.SPControl]::SetContextWeb([System.Web.HttpContext]::Current, $web)

    #do stuff

    [System.Web.HttpContext]::Current = $null

    ReplyDelete