Using ImportWebPart method in internet facing SharePoint WCM Site

 

Introduction

In many instances we use ImportWebPart method of the WebpartManager class to import web parts in runtime. If you are using this method to render dynamic content in an anonymous internet facing site using SharePoint there are few points to be noted. Out of the box WebpartManager class expects certain permissions to successfully import a Web part in anonymous mode and the same has been implemented using Code Access Security. Permissions required will not be available in anonymous mode. Following article articulates a design to handle this. Keep reading….

What happens if you use out of the box WebPartManager Class?

Out of the box WebpartManager class works as expected in authenticated mode. If you have the site extended to anonymous mode you can notice that the pages hosting a web part or user control which dynamically hosts another web part instance using ImportWebPart Method will start challenging for credentials. First suspect for this might be to check whether you have published version of the page. After few hours of trouble shooting you may find that all pre-requisites are met and still the pages challenges for credentials. This is due to the fact that the out of box WebPartManager class expects certain permissions in runtime and the same is not available in anonymous mode. Next step is to run the code with Elevated privileges. This will not help the WebPartManager to get the needed permissions.

What’s going on in WebPartManager Class?

As per MSDN  documentation WebPartManger class of SharePoint is designed to be used only in authenticated mode. But the design does not restrict us to extend the same based on our custom requirements. Important sections from the MSDN article.

image

image

What's the solution to use this in Anonymous mode?

To overcome the above mentioned limitation we need to create a custom WebPartManager with custom set of permissions. Below mentioned code snippet can be used directly to create the class. I have tested this in a big WCM site and the code has no bugs :)

Custom Web part Manager and Personalization class

    1: /// <summary>
    2:    /// Personalization class
    3:    /// </summary>
    4:    public class CustomWebPartPersonalization : WebPartPersonalization
    5:    {
    6:        /// <summary>
    7:        ///  Importing bool property
    8:        /// </summary>
    9:        internal bool Importing;
   10:  
   11:        /// <summary>
   12:        /// Initializes a new instance of the CustomWebPartPersonalization class
   13:        /// </summary>
   14:        /// <param name="owner">constructor default</param>
   15:        public CustomWebPartPersonalization(WebPartManager owner)
   16:            : base(owner)
   17:        {
   18:        }
   19:  
   20:        /// <summary>
   21:        /// User Capabilities
   22:        /// </summary>
   23:        protected override IDictionary UserCapabilities
   24:        {
   25:            get
   26:            {
   27:                IDictionary userCapabilities = base.UserCapabilities;
   28:                if (this.Importing)
   29:                {
   30:                    userCapabilities[WebPartPersonalization.ModifyStateUserCapability] =
   31:                        WebPartPersonalization.ModifyStateUserCapability;
   32:                }
   33:  
   34:                return userCapabilities;
   35:            }
   36:        }
   37:    }
   38:  
   39:    /// <summary>
   40:    /// Custom Web part manager
   41:    /// </summary>
   42:    public class CustomWebPartManager : WebPartManager
   43:    {
   44:        /// <summary>
   45:        ///  Import web part
   46:        /// </summary>
   47:        /// <param name="reader">reader object</param>
   48:        /// <param name="errorMessage">error message</param>
   49:        /// <returns>web part returned</returns>
   50:        public override System.Web.UI.WebControls.WebParts.WebPart ImportWebPart(System.Xml.XmlReader reader, out string errorMessage)
   51:        {
   52:            ((CustomWebPartPersonalization)Personalization).Importing = true;
   53:            System.Web.UI.WebControls.WebParts.WebPart webPart = base.ImportWebPart(reader, out errorMessage);
   54:            ((CustomWebPartPersonalization)Personalization).Importing = false;
   55:            return webPart;
   56:        }
   57:  
   58:        /// <summary>
   59:        ///  Create Personalization
   60:        /// </summary>
   61:        /// <returns>web part returned</returns>
   62:        protected override WebPartPersonalization CreatePersonalization()
   63:        {
   64:            WebPartPersonalization obj = base.CreatePersonalization();
   65:            return new CustomWebPartPersonalization(this);
   66:        }
   67:    }

 

Implementation or Usage Code

    1: /// <summary>
    2: /// Method to get the webpart instance based on the web part xml string. XML string passed 
    3: /// to the method should adhere to the schema of the xml used in .webpart file. 
    4: /// </summary>
    5: /// <param name="webPartXml">The web part XML.</param>
    6: /// <returns>WebPart Instance</returns>
    7: private static System.Web.UI.WebControls.WebParts.WebPart GetWebPartInstance(string webPartXml)
    8: {
    9:     StringReader stringReader = new StringReader(webPartXml);
   10:     XmlReader xmlReader = XmlReader.Create(stringReader);
   11:     string errorMessage;
   12:  
   13:     //// Use webpart manager to instantiate the webpart using xml
   14:     //// System.Web.UI.WebControls.WebParts.WebPart wp = WebPartManager.ImportWebPart(xmlReader, out errorMessage);
   15:  
   16:     //// Using custom web part manager with needed permissions to import the web part in anonymous mode.
   17:  
   18:     CustomWebPartManager webPartManager = new CustomWebPartManager();
   19:     System.Web.UI.WebControls.WebParts.WebPart wp = webPartManager.ImportWebPart(xmlReader, out errorMessage);
   20:     //// Set the properties on webpart
   21:     wp.AllowClose = false;
   22:     wp.AllowEdit = false;
   23:     wp.AllowMinimize = false;
   24:     wp.AllowZoneChange = false;
   25:     wp.AllowConnect = false;
   26:     wp.AllowHide = false;
   27:     wp.ExportMode = WebPartExportMode.None;
   28:     wp.ChromeType = PartChromeType.None;
   29:     //// Return the webpart
   30:     return wp;
   31: }

Happing coding :)

Technorati Tags: Sharepoint,Webparts,WebPartManager,ImportWebPart