Export and import webparts programmatically

Requirement:-

I have 1 site Where it has sharepoint page’s with some webparts. Due to business requirement; we need to export these webpart and import on other site page programmatically.

Therefore I created a tool which first exports webparts (.webpart file) and metadata in xml format, then import web part on other site using xml and .webpart file.

NOTE:
Important point is if we have connected web part on web page then we need to care about their mapping.
So I will be using “SPLimitedWebPartManager.SPConnectWebParts” method to connect webpart while import. This will require a mapping which I will get in during export process in my custom method “FindConnectedWebPart”.

Export Tool

        /// <summary>
        /// this is main function of your console application.
        /// This initiate process of export webparts
        /// </summary>
        private void Main(string[] args)
        {
            url = base.Params["url"].Value; // site url
            // you can generate your own xml path
            xmlFile = strFolderPath + "\" + Path.GetFileNameWithoutExtension(base.Params["page"].Value) + ".xml";
            string page = "/pages/" + base.Params["page"].Value; // sharepoint page path

            List<SiteWebPart> siteWebparts = new List<SiteWebPart>();

            using (SPSite oSite = new SPSite(url))
            {
                using (SPWeb oWeb = oSite.OpenWeb())
                {
                    var newDefaultPage = oWeb.GetFile(url + page);
                    Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager wpm =
                       newDefaultPage.GetLimitedWebPartManager(PersonalizationScope.Shared);
                    siteWebparts = ExportWebpart(wpm, siteWebparts);
                    siteWebparts = FindConnectedWebPart(wpm, siteWebparts);
                    // i have big hierarchey like having XSD schema then proper class for xsd
                    // then save file using specific xsd schema format...
                    // therefore i can not detail all those. But in short you need to read
                    // read siteWebparts object and save data into xml.
                    // This xml is your own defined format which can hold all web part properties
                    SaveToFile(xmlFile); // write your own method to save xml file.
                    wpm.Dispose();
                }
            }
        }

        /// <summary>
        /// It find the webpart connection on page and store into SiteWebPart 
        /// object which will finally get store into xml file.
        /// </summary>
        /// <param name="wpm">SPLimitedWebPartManager object for source pageurl</param>
        /// <param name="siteWebParts">Collection of webparts which get export</param>
        /// <returns></returns>
        private List<SiteWebPart> FindConnectedWebPart(SPLimitedWebPartManager wpm, List<SiteWebPart> siteWebParts)
        {
            SPWebPartConnectionCollection webPartConColl = wpm.SPWebPartConnections;
            try
            {
                foreach (SPWebPartConnection webPartCon in webPartConColl)
                {
                    string strProviderTitle = RemoveSpecialCharacters(webPartCon.Provider.Title);
                    string strConsumerTitle = RemoveSpecialCharacters(webPartCon.Consumer.Title);
                    SiteWebPart webpartSetting = siteWebParts.Find(e => e.Settings.Title == strProviderTitle);
                    TransformableFilterValuesToFilterValuesTransformer transformerMapping =
                        (TransformableFilterValuesToFilterValuesTransformer)webPartCon.Transformer;

                    if (webpartSetting != null)
                    {
                        webpartSetting.Settings.ConsumerWebPart = strConsumerTitle;
                        webpartSetting.Settings.ProviderWebPart = strProviderTitle;
                        webpartSetting.Settings.MappingId = transformerMapping.MappedConsumerParameterName;

                        if (String.Compare(webPartCon.Provider.GetType().Name, "SPSlicerTextWebPart", true) == 0)
                        {
                            webpartSetting.Settings.FilterName =
                                ((Microsoft.SharePoint.Portal.WebControls.SPSlicerBaseWebPart)(webPartCon.Provider)).FilterName;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // message
            }
            return siteWebParts;
        }

        /// <summary>
        /// It export all webparts in ".webpart" file format, into folder path
        /// </summary>
        /// <param name="wpm">SPLimitedWebPartManager object for source pageurl</param>
        /// <param name="siteWebParts">Collection of webparts which get export</param>
        /// <returns></returns>
        private List<SiteWebPart> ExportWebpart(SPLimitedWebPartManager wpm, List<SiteWebPart> siteWebparts)
        {

            XmlTextWriter writer;
            foreach (var webPartOnPage in wpm.WebParts)
            {
                try
                {
                    System.Web.UI.WebControls.WebParts.WebPart webPartObj =
                          (System.Web.UI.WebControls.WebParts.WebPart)(webPartOnPage);
                    // strFolderPath is my own custom path where i will store all .webpart file.
                    string strFilePath = strFolderPath + "\" + RemoveSpecialCharacters(webPartObj.Title) + ".webpart";
                    if (!Directory.Exists(strFolderPath))
                    {
                        Directory.CreateDirectory(strFolderPath);
                    }

                    SiteWebPart siteWebpart = new SiteWebPart();
                    SiteWebPartSettings rootSite = new SiteWebPartSettings();
                    rootSite.Title = RemoveSpecialCharacters(webPartObj.Title);
                    rootSite.ZoneId = wpm.GetZoneID(webPartObj);
                    rootSite.ZoneIndexSpecified = true;
                    rootSite.ZoneIndex = webPartObj.ZoneIndex;
                    rootSite.AssemblyType = webPartObj.GetType().AssemblyQualifiedName;
                    siteWebpart.Settings = rootSite;
                    siteWebparts.Add(siteWebpart);
                    writer = new XmlTextWriter(strFilePath, Encoding.UTF8);
                    wpm.ExportWebPart(webPartObj, writer);
                    writer.Flush();
                    writer.Close();
                }
                catch { }

            }
            return siteWebparts;
        }

        /// <summary>
        /// Remove all Characters which are not allowed to store on filesystem
        /// </summary>
        /// <param name="fileName">source file name</param>
        /// <returns>updated file name</returns>
        private string RemoveSpecialCharacters(string fileName)
        {
            try
            {
                string[] specialChars = new string[] { "\", "/", ":", "*", "?", """, "<", ">", "|" };
                foreach (string eachString in specialChars)
                {
                    fileName = fileName.Replace(eachString, "");
                }
            }
            catch (Exception ex)
            {
                SPOperation.Log("Error in RemoveSpecialCharacters() function: " + ex.Message);
            }

            return fileName;
        }


Import Tool

 /// <summary>
        /// This is function initiate the process of import.
        /// </summary>
        private void Main(string[] args)
        {
            siteUrl = base.Params["url"].Value; // site url
            strPageUrl = siteUrl + "/pages/" + base.Params["page"].Value; // sharepoint page path
            // get folder path. Note i have folder naming specific to page name.
            // and every folder had 1 xml and 1 webpart file
            strFolderPath = base.Params["folder"].Value + "\" + Path.GetFileNameWithoutExtension(base.Params["page"].Value);
            string strFile = new DirectoryInfo(strFolderPath).GetFiles("*.xml")[0].FullName; // get the xml file to specific page.
            // i have big hierarchey like having XSD schema then proper class for xsd
            // then Load file using specific xsd schema format...
            // therfore i can not detail all those. But in short you need to Load xml 
            // and store webpart property into a object (for me its custom class "SiteWebPart" 
            // and return List<SiteWebPart> 
            List<SiteWebPart> siteWebParts = LoadFromFile(strFile);

            try
            {
                using (SPSite oSite = new SPSite(siteUrl))
                {
                    using (SPWeb oWeb = oSite.OpenWeb())
                    {
                        string strZoneId = string.Empty;
                        int ZoneIndex = 0;
                        DirectoryInfo dir = new DirectoryInfo(strFolderPath);
                        if (force)
                            DeleteWebPart(oWeb);
                        foreach (FileInfo f in dir.GetFiles("*.webpart"))
                        {
                            strZoneId = siteWebParts.Where(e => e.Settings.Title == Path.GetFileNameWithoutExtension(f.Name)).Select
                                               (e => e.Settings.ZoneId).ToArray()[0].ToString();
                            string strTemp = siteWebParts.Where(e => e.Settings.Title == Path.GetFileNameWithoutExtension(f.Name)).Select
                                          (e => e.Settings.ZoneIndex).ToArray()[0].ToString();
                            if (!String.IsNullOrEmpty(strTemp))
                                ZoneIndex = int.Parse(strTemp);

                            if (f.Length == 0)
                            {
                                AddWebPartToPageUsingAssembly(Path.GetFileNameWithoutExtension(f.Name), oWeb, strZoneId, ZoneIndex, siteWebParts);
                                continue;
                            }

                            AddWebPartToPage(f.FullName, oWeb, strZoneId, ZoneIndex);
                        }
                        ConnectWebPartOnPage(oWeb, siteWebParts);
                    }
                }
            }
            catch (Exception ex)
            {
                // exception
            }

            Console.Read();
        }

        /// <summary>
        /// Add webpart file to sharepoint page
        /// </summary>
        /// <param name="webPartFullName">Full path of web part file</param>
        /// <param name="web">Web object of site</param>
        /// <param name="strZoneId">Zone location where web part will get add</param>
        /// <param name="zoneIndex">webpart index for zone</param>
        public void AddWebPartToPage(string webPartFullName, SPWeb web, string zoneId, int zoneIndex)
        {
            SPFile file = null;
            XmlUrlResolver xmlResolver = new XmlUrlResolver();
            xmlResolver.Credentials = CredentialCache.DefaultCredentials;
            FileStream fs = new FileStream(webPartFullName, FileMode.OpenOrCreate);
            XmlReader reader = new XmlTextReader(fs);
            string errorMsg;
            SPLimitedWebPartManager manager = null;

            try
            {
                file = web.GetFile(strPageUrl);
                if (file.CheckOutStatus == SPFile.SPCheckOutStatus.None)
                {
                    file.CheckOut();
                    manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
                    System.Web.UI.WebControls.WebParts.WebPart tempWebPart = 
                       manager.ImportWebPart(reader, out errorMsg);
                    manager.AddWebPart(tempWebPart, zoneId, zoneIndex);
                    web.Update();
                }
            }
            catch (Exception ex)
            {
                // exception
            }
            finally
            {
                if (manager != null)
                    manager.Dispose();

                if (file != null)
                {
                    file.CheckIn("added web parts");
                    file.Publish("added web parts");
                }
                if (fs != null)
                {
                    fs.Close();
                    fs.Dispose();
                }

            }
        }

        /// <summary>
        /// Add webpart using assembly/class to sharepoint page
        /// </summary>
        /// <param name="strWebPartName">Web part Name</param>
        /// <param name="oWeb">Web object of site</param>
        /// <param name="strZoneId">Zone location where web part will get add</param>
        /// <param name="ZoneIndex">webpart index for zone</param>
        /// <param name="siteWebParts">Collection of webparts which need to import</param>
        private void AddWebPartToPageUsingAssembly(string strWebPartName, SPWeb oWeb, string strZoneId, int ZoneIndex, List<SiteWebPart> siteWebParts)
        {
            SPFile file = null;
            SPLimitedWebPartManager manager = null;
            SiteWebPart webpartSetting = siteWebParts.Find(e => e.Settings.Title == strWebPartName);

            try
            {
                if (webpartSetting != null)
                {
                    string strType = webpartSetting.Settings.AssemblyType;
                    Type type = Type.GetType(strType);
                    Assembly assemblyType = type.Assembly;
                    System.Web.UI.WebControls.WebParts.WebPart webPartObj = 
                          (System.Web.UI.WebControls.WebParts.WebPart)assemblyType.CreateInstance(type.FullName);
                    webPartObj.ChromeType = PartChromeType.None;
                    webPartObj.Title = webpartSetting.Settings.Title;
                    if (String.Compare(webPartObj.GetType().Name, "SPSlicerTextWebPart", true) == 0)
                    {
                        (((Microsoft.SharePoint.Portal.WebControls.SPSlicerBaseWebPart)(webPartObj))).FilterName = webpartSetting.Settings.FilterName;
                    }
                    file = oWeb.GetFile(strPageUrl);

                    if (file.CheckOutStatus == SPFile.SPCheckOutStatus.None)
                    {
                        file.CheckOut();
                        manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
                        manager.AddWebPart(webPartObj, strZoneId, ZoneIndex);
                        oWeb.Update();
                    }
                }

            }
            catch (Exception ex)
            {
                //Exception
            }
            finally
            {
                if (manager != null)
                    manager.Dispose();

                if (file != null)
                {
                    file.CheckIn("added web parts");
                    file.Publish("added web parts");
                }
            }
        }

        /// <summary>
        /// Delete all webparts and web part connection from destination site
        /// </summary>
        /// <param name="oWeb">Web object of site</param>
        private void DeleteWebPart(SPWeb oWeb)
        {
            SPFile file = null;
            SPLimitedWebPartManager manager = null;
            file = oWeb.GetFile(strPageUrl);
            try
            {
                if (file.CheckOutStatus == SPFile.SPCheckOutStatus.None)
                {
                    file.CheckOut();
                    manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
                    manager.SPWebPartConnections.Clear();
                    for (int j = 0; j < manager.SPWebPartConnections.Count; j++)
                        manager.SPWebPartConnections.RemoveAt(0);
                    int wpCount = manager.WebParts.Count - 1;
                    for (; wpCount >= 0; --wpCount)
                        manager.DeleteWebPart(manager.WebParts[wpCount]);
                }
            }
            catch (Exception ex)
            {
                SPOperation.Log("Error in DeleteWebPart() function: " + ex.Message);
            }
            finally
            {
                if (manager != null)
                    manager.Dispose();

                if (file != null)
                {
                    file.CheckIn("Deleted all web parts");
                    file.Publish("Deleted all web parts");
                }
            }

        }

        /// <summary>
        /// It connect web parts each others, if any, using consumer and provider objects
        /// </summary>
        /// <param name="oWeb">Web object of site</param>
        /// <param name="siteWebParts">Collection of webparts which need to import</param>
        private void ConnectWebPartOnPage(SPWeb oWeb, List<SiteWebPart> siteWebParts)
        {
            List<SiteWebPart> siteFilterWebParts = siteWebParts.FindAll(e => e.Settings.MappingId != null);
            SPFile file = null;
            SPLimitedWebPartManager manager = null;
            file = oWeb.GetFile(strPageUrl);

            try
            {
                if (file.CheckOutStatus == SPFile.SPCheckOutStatus.None)
                {
                    file.CheckOut();
                    manager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);

                    foreach (SiteWebPart siteWebPart in siteFilterWebParts)
                    {
                        string strConsumerWebPartName = siteWebPart.Settings.ConsumerWebPart;
                        string strProviderWebPartName = siteWebPart.Settings.ProviderWebPart;

                        System.Web.UI.WebControls.WebParts.WebPart webPartConsumer = null;
                        System.Web.UI.WebControls.WebParts.WebPart webPartProvider = null;

                        var mgConsumerWebPart = 
                              manager.WebParts.Cast<System.Web.UI.WebControls.WebParts.WebPart>().Where(e => e.Title == 
                                                                                                      strConsumerWebPartName);
                        var mgProviderWebPart = 
                           manager.WebParts.Cast<System.Web.UI.WebControls.WebParts.WebPart>().Where(e => e.Title == 
                                                                                                     strProviderWebPartName);

                        if (mgConsumerWebPart.Count() > 0)
                            webPartConsumer = mgConsumerWebPart.ElementAt(0);
                        if (mgProviderWebPart.Count() > 0)
                            webPartProvider = mgProviderWebPart.ElementAt(0);

                        ConsumerConnectionPoint consumerConnection = null;
                        foreach (ConsumerConnectionPoint point in manager.GetConsumerConnectionPoints(webPartConsumer))
                        {
                            if (point.InterfaceType == typeof(IFilterValues))
                            {
                                consumerConnection = point; break;
                            }
                        }
                        ProviderConnectionPoint providerConnection = null;
                        foreach (ProviderConnectionPoint point in manager.GetProviderConnectionPoints(webPartProvider))
                        {
                            if (point.InterfaceType == typeof(Microsoft.SharePoint.WebPartPages.ITransformableFilterValues))
                            {
                                providerConnection = point; break;
                            }
                        }

                        TransformableFilterValuesToFilterValuesTransformer transformMapping = new TransformableFilterValuesToFilterValuesTransformer();
                        transformMapping.MappedConsumerParameterName = siteWebPart.Settings.MappingId;
                        manager.SPConnectWebParts(webPartProvider, providerConnection, webPartConsumer, consumerConnection, transformMapping);
                        //manager.SPWebPartConnections.Add(conn);

                        oWeb.Update();
                    }

                }
            }
            catch (Exception ex)
            {
                //Exception
            }
            finally
            {
                if (manager != null)
                    manager.Dispose();

                if (file != null)
                {
                    file.CheckIn("Connected web parts, if any");
                    file.Publish("Connected web parts, if any");
                }
            }
        }


Common class for export and import tool

    public partial class SiteWebPart
    {

        public string Title {
            get {
                return this.titleField;
            }
            set {
                this.titleField = value;
            }
        }

        public string ZoneId {
            get {
                return this.zoneIdField;
            }
            set {
                this.zoneIdField = value;
            }
        }

        public int ZoneIndex {
            get {
                return this.zoneIndexField;
            }
            set {
                this.zoneIndexField = value;
            }
        }

        public bool ZoneIndexSpecified {
            get {
                return this.zoneIndexFieldSpecified;
            }
            set {
                this.zoneIndexFieldSpecified = value;
            }
        }

        public string AssemblyType
        {
            get
            {
                return this.assemblyTypeField;
            }
            set
            {
                this.assemblyTypeField = value;
            }
        }

        public string ConsumerWebPart {
            get {
                return this.consumerWebPartField;
            }
            set {
                this.consumerWebPartField = value;
            }
        }

        public string ProviderWebPart {
            get {
                return this.providerWebPartField;
            }
            set {
                this.providerWebPartField = value;
            }
        }

        public string MappingId {
            get {
                return this.mappingIdField;
            }
            set {
                this.mappingIdField = value;
            }
        }

        public string FilterName {
            get {
                return this.filterNameField;
            }
            set {
                this.filterNameField = value;
            }
        }
    }

 

Issues and Resolutions during implementation:-

==========================================================================

This above tool also resolve this issue:-

SPLimitedWebpartManager.ExportWebPart(Webpart, XmlWriter) throws XmlException
like below:-
The prefix ” cannot be redefined from ” to ‘http://schemas.microsoft.com/WebPart/v3’ within the same start element tag.
Solution:- Then change xmlwriter to xmltextwriter. Same you can see in my above tool.

==========================================================================

Above tool also handle this biggest issue which i face :-

SPLimitedWebpartManager.ExportWebPart(Webpart, XmlWriter) throws XmlException
XmlException when you use Text Filter Web Part (SPSlicerTextWebPart)
As per understanding, There is no solution for this. So I have other work around for this.
Why we are exporting? Since we might want import to some other site.
So what we can do, while export, store webpart detail in xml file. And while import creates 2 function as mentioned below:-

1. this is for those which have .webpart file

for this use “AddWebPartToPage” function which can be view in above article.

2. This is: for those who does not have webpart file means it couldn’t export.
For this use “AddWebPartToPageUsingAssembly” function which can be also view in above article.

===============================================================

any exception comes like this:-
Throws this error on ImportWebPart…”The file you imported is not
valid. Verify that the file is a Web Part description file (*.webpart
or *.dwp) and that it contains well-formed XML.”

then its issue with credential. please us CredentialCache.DefaultCredentials

===============================================================

any exception comes like this:-
“Object reference not set to an instance of an object” while ImportWebPart
then its isse with loading file. Dont use File to load use FileStream as mentioned in above function.

===============================================================

Thanks!
Avinash

calendarMarch 13, 2012 · cardInfoyen · comments4 Comments
tagTags: , , , , , , , , , ,  · Posted in: MOSS, SharePoint

4 Responses

  1. Saul Rotblatt - May 15, 2012

    What is the import statement for SiteWebPart. I cannot find this class defined in any online documentation?

    Thanks,

    Saul

  2. Saul Rotblatt - May 15, 2012

    Ignore my last comment, I didn’t scroll down and see the partial class. My bad, definitely need more sleep.

    Saul

  3. Bruno - June 27, 2012

    Hi,

    Where is the SiteWebPartSettings?
    “SiteWebPartSettings rootSite = new SiteWebPartSettings();”

    In the SiteWebPart class, the attributes in the getters and setters don’t match, it is supose?

    Thank you.

  4. Infoyen - June 27, 2012

    Hi Bruno,

    Thanks for your question.
    My goal is to share the idea. But truly it may not be just copy paste..
    As you can see “SiteWebPartSettings” is nothing but entity class. so you can create easily its no big deal.
    Also about “SiteWebPart” class: if you feel i have more property or less then you can respectively add or remove.

    you can customize this code as per you requirement.

    However i have wrote entity class for “SiteWebPartSettings” which is mentioned below:-

    public partial class SiteWebPartSettings
    {

    public string Title {get;set;}
    public string ZoneId {get;set;}
    public int ZoneIndex {get;set;}
    public bool ZoneIndexSpecified {get;set;}
    public string AssemblyType {get;set;}

    }

    Thanks & Regards,
    Avinash

Leave a Reply

Spam Protection: , required

myworldmaps infoyen