What to know about SmartPart, and LoadControl()

At Infusion ASP.NET developers regularly ask how to easily build a web part or how to host a user control (.ascx) in SharePoint. Someone invariably replies "SmartPart!" at which point my job is to make sure they understand what they're getting into.

SmartPart is a cleverly coded web part by fellow MOSS MVP Jan Tielens. Once installed, you can drag an instance of SmartPart into a SharePoint web part zone and configure the new web part to host an .ascx file stored in the file system. And like magic, you can host user controls in SharePoint. Recent versions (v1.3+) are AJAX-aware, support web part connections, and improved the deployment story, and the underlying code is really quite good.

But, there are drawbacks, some of which may be overcome, some of which are realities.

1. SmartPart examples set web.config to Full Trust. Not for the web part, but for the entire SharePoint application. You do not want to do this in Production, and happily this is avoidable. However, it does mean that you can't avoid the pain of creating a CAS policy (e.g. if your controls require access to the SharePoint API or unmanaged resources) by using the SmartPart.

2. SmartPart is an open source project, but the download contains only its classes so you can't compile it without some work of your own. If you work for clients who want to use SmartPart, I strongly recommend building your own SmartPart project as a starting point, and maintaining that code base as new features are added to the CodePlex project. While you won't "own" the code (copyright rules would say it's still Jan's and you should attribute it as such), you will now have full control and accountability for the code running on your servers, as it should be.

3. The SmartPart disclaimer defines exactly what to expect should things go wrong, or should you need to extend its capabilities: ". . . the Software comes 'as is', with no warranties. None whatsoever. This means no express, implied or statutory warranty, including without limitation, warranties of merchantability or fitness for a particular purpose or any warranty of title or non-infringement." Part of the license is to distribute this license whenever SmartPart is used. 

To be fair, this disclaimer is similar to many software licenses, and all open source licenses. Linux is open source and offers no support. When things go wrong with Linux, Linus Torvalds will not show up at your door to hold your hand. To make Linux palatable for Production, Red Hat sells support. If you pay extra, they may even hold your hand.

SmartPart carries no support, and no commercial version exists that would provide support. But, if you follow the advice of the last point and create you own project so you have control of the code, you can support your own. This is what you want to avoid: there was a period of several months after GotDotNet was decommissioned and SmartPart did not yet exist on CodePlex. During this time it was impossible to download any "official" version of SmartPart, current or otherwise. had the source been released earlier (it wasn't) this wouldn't have inconvenienced anyone. From now on should the source become unavailable for any reason, you'll only have yourself to blame. 

4. Building a custom web part that uses LoadControl() to host a user control is not difficult, and SmartPart's source code is a great way to learn how! The sample code below shows you how to load a user control and interact with its content from a web part, in this case to retrieve the content of a SharePoint list and implement paging.

Using the sample code

This is intended to roughly parallel the Smartpart - the user control will go into a usercontrols folder at the root of your application and the web part's assembly can be deployed to the GAC unless you'd like to write a CAS policy to deploy it to the bin folder.

Place the ascx in a \usercontrols folder into the Web Application's root (e.g. C:\Inetpub\wwwroot\wss\VirtualDirectories\80\usercontrols).

Create the web part, sign the project and add a line like this to the SafeControls section of web.config. Remember to replace the Assembly attribute with your own, best obtained by opening your assembly with Reflector:
      <SafeControl Assembly="LoadControlWP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=myToken" Namespace="LoadControlWP" TypeName="LoadControlWebPart" Safe="True" />

Then get your web part's assembly into the GAC and recycle the application pool, or build a CAS policy (if you control requires it) and place it in the web application's bin folder.

 

Sample code (LoadControlWP.cs): 

using System;
using System.Collections.Generic;
using System.Text;

using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Web.UI.WebControls.WebParts;
using System.Diagnostics;
using Microsoft.SharePoint;

namespace LoadControlWP
{
    public class LoadControlWebPart : System.Web.UI.WebControls.WebParts.WebPart
    {
        private UserControl usercontrol;
        private GridView gvDemo;
        private const string defaultlist = "";
        private string _listtolink = defaultlist;
        protected DataTable dtDemo = null;

        [Personalizable(), WebBrowsable(),
        WebDisplayName("List to display"),
        WebDescription("Name of the list in this site to display")]
        public string ListToLink
        {
            get { return _listtolink; }
            set { _listtolink = value; }
        }

        protected override void CreateChildControls()
        {
            try
            {
                base.CreateChildControls();
                this.Controls.Clear();
                this.GetData();
                usercontrol = (UserControl)Page.LoadControl(@"/usercontrols/wpgrid.ascx");

                gvDemo = (GridView)this.usercontrol.FindControl("gvDemo");
                gvDemo.AllowPaging = true;
                gvDemo.DataSource = dtDemo;
                gvDemo.PageSize = 3;
                gvDemo.PageIndexChanging += new GridViewPageEventHandler(gvDemo_PageIndexChanging);
                this.Controls.Add(usercontrol);

                gvDemo.DataBind();
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("WebParts", "UCWebPart" + ex.ToString());
            }
        }

        void gvDemo_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {

            gvDemo.PageIndex = e.NewPageIndex;
            gvDemo.DataBind();
        }

        private void GetData()
        {
            try
            {
                if (ListToLink.Length > 0)
                {
                    dtDemo = new DataTable();
                    dtDemo.Columns.Add("Title", Type.GetType("System.String"));

                    SPWeb site = SPContext.Current.Web;
                    SPList list = site.Lists[_listtolink];

                    foreach (SPListItem item in list.Items)
                    {
                        DataRow newRow = dtDemo.NewRow();
                        newRow["Title"] = item["Title"];
                        dtDemo.Rows.Add(newRow);
                    }
                }
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("WebParts", "UCWebPart - Retrieving items from " + _listtolink + "-" + ex.ToString(), EventLogEntryType.Error);
            }
        }
    }
}

 

Sample code (wpgrid.ascx):

<%@ Control Language="C#" ClassName="WebUserControl" %>

<script runat="server">

</script>

<asp:GridView ID="gvDemo" runat="server" AutoGenerateColumns="False" CellPadding="4" ForeColor="#333333" GridLines="None">
    <Columns>
        <asp:BoundField DataField="Title" HeaderText="Title" />
    </Columns>
    <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
    <EditRowStyle BackColor="#999999" />
    <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
    <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
    <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
    <AlternatingRowStyle BackColor="White" ForeColor="#284775" />
</asp:GridView>

 

No Comments