SharePoint has been around for quite some time. I first worked with it in its original version in 2001. And so began a love hate relationship that has lasted these many years.
Recently I have been spending a significant amount of time writing custom web parts. Below are a number of notes I have accumulated while rediscovering what SharePoint can do. I don’t claim that these are best practices, only that they have worked for me.
Creating web parts for WSS 3.0 or MOSS 2007 requires Visual Studio 2005 or Visual Studio 2008. There is a downloadable package Visual Studio Extensions for Windows SharePoint Services 3.0. The problem with this particular tool is that it requires that you develop on a machine with Windows Server 2003 or Windows Server 2008 as an operating system. Developing on a stand alone desktop/laptop while referencing the main SharePoint assembly can be much simpler. It is a trade off between licenses issues and portability challenges versus a lack of productivity tools. For this discussion we will assume a stand alone, non-server environment.
WSPBuilder is a CodePlex project for creating SharePoint solution files. Besides packaging web parts it is also a tool for packaging features and workflows. The tool can be downloaded from the following location:
Starting A Web Part
Web Parts are really just specialized web server control. That being said, creating a web server control is the perfect place to start and then modify it for SharePoint. Alternately you could start with an ASP.NET web part. The caution here is that they implement a different set of events.
One of the first things you will need to do is to change the class that the control inherits from to Microsoft.SharePoint.WebPartPages.WebPart.
Additionally you will need to add the following import statements:
Adding Web Part Properties
Web Part Properties are the definition of the settings which allow you to configure a web part once you have placed it on a page. They start out the same as any C# property with a getter and setter. The main difference are the attributes that are applied to the property.
[Category("User Creation Settings")]
[FriendlyName("Role Provider Name")]
[Description("Name of the membership role provider")]
[XmlElement(ElementName = "roleProvider")]
public string ProviderName
_ProviderName = value;
Adding controls to a web part
There isn’t a designer for creating web parts. The process reminds me of C++ MFC development. You have to define, instantiate and position all of your controls through code. I have seen some possible short cuts be first creating user controls, but the process seemed a little hackish and I haven’t tested it yet.
First you should define the controls globally in your class.
Once you have your controls defined you instantiate them in the CreateChildControls override method. This is also the point where you wire up any event handler methods. The code below is an example of the techniques that can be used.
_FirstName= new TextBox();
_FirstName.CssClass = "my-textbox";
_OptionType= new DropDownList();
_CreateUser = new Button();
_CreateUser.CssClass = "my-button";
_CreateUser.Text = "Create User";
_CreateUser.Click += new EventHandler(_CreateUser_Click);
_Message = new Label();
_Message.CssClass = "my-errorMessage";
The last step in order to display controls for use in your web part is to implement the RenderContents override method. This method uses a HtmlTextWriter object to render the tags for the UI of your web part. The most straight forward, although not necessarily the simplest, way to do this is to write out the text of your layout tags and them pass the writer object to your controls so that they can render themselves. Alternately you can do your layout entirely through rendering controls which represent all of your resulting HTML tags. Below is an example of the first approach.
Essential SharePoint Objects
The most important classes within the SharePoint object model represent the hierarchy of the SharePoint. These are the SPWeb and SPSite classes. SPWeb represents a SharePoint web application as you would configure in Central Administration. SPSite represents a site collection.
You do not always have to instantiate these classes explicitly, although there are some cases where that is a requirement.
Adding users to security groups
Managing SharePoint security for end users can be very confusing. One way to alleviate this burden is to create a web part that abstracts away the details. The main class used to facilitate this capability is SPGroup.
There are two critical things to note in the code below. The first is the fact that it is written as an inline delegate to elevate the privileges of the current user.
The second thing to note is the use of the AllowUnsafeUpdates property of the SPWeb object.
SPSite newSite = new SPSite(_SiteUrl);
SPWeb web = newSite.OpenWeb();
web.AllowUnsafeUpdates = true;
SPGroup candidateGroup = web.Groups[_SharepointGroup];
candidateGroup.AddUser(fullyQualifiedUserID, _Email.Text, userName, string.Empty);
Adding items to lists
The topic of lists covers both SharePoint Lists and Document Libraries. They are both essentially list, except for one puts more emphasis on attachments than the other. Because of this they can be treated the same in many respects. The code below adds a file to a document library and then sets values for columns on that list.
SPFolder folder = web.GetFolder(_Folder);
SPFile sourceFile = web.GetFile(_TemplateUrl);
string folderUrl = folder.ServerRelativeUrl + "/";
string fileName = _BaseFileName + ".xml";
sourceFile.CopyTo(folderUrl + fileName);
SPFile newFile = folder.Files[fileName];
newFile.Item["First Name"] = _FirstName.Text;
newFile.Item["Last Name"] = _LastName.Text;
newFile.Item["Full Name"] = _LastName.Text + ", " + _FirstName.Text;
newFile.Item["Preferred Name"] = _PreferredName.Text;
newFile.Item["Appointment Type"] = _OptionType.SelectedItem.Text;
Notice that the last line calls the Update method on the item. If this call is not made then your changes will not be saved.
Deploying SharePoint web parts can be tedious and problematic. While installing them by hand is possible solution files make the process somewhat easier to manage. At the beginning of the paper I mentioned WSPBuilder. The WSP stands for WSS Solution Project. What these boil down to are CAB files which include deployable objects and a manifest of the contents. WSPBuilder simplifies the creation of these files.
There are two ways that this can be accomplished. Installing the WSPBuilder gives you Visual Studio extensions as well as new Visual Studio templates. The former simply packages the assembly of a project and creates safe control entries for your web.config file.
Adding the solution to SharePoint using stsadm
Once you have created a solution you need to copy it to the server that Central Admin resides on. There you will use the stsadm command line tool to install the solution. Execute the following command, making sure to modify the filename parameter value for the location you copied the wsp file to.
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsadm -o addsolution -filename "d:\webparts\MyWebPart.wsp"
Deploying solution through Central Admin
The only time that I have found that I needed to access Central Admin for a web part solution is initial deployment or to remove a solution.
In order to deploy the web part solution that was added during the previous section you need to navigate to Solution Management from the Operations tab in Central Admin. There you will see a list of solutions. From there click on the solution that you want to deploy and click the Deploy Solution button at the top of the screen that appears.
Upgrading a solution to SharePoint using stsadm
Interestingly, there are more parameters required to upgrade a solution then there are to install it in the first place. This is mostly due to the functions that are taken care of by the Central Admin deployment capabilities.
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN>stsadm -o upgradesolution -filename "d:\webparts\MyWebPart.wsp" -name " MyWebPart.wsp" -immediate –allowGacDeployment
Note: If you do not keep the same version number for the assembly you will break any pages that already contain the web parts contained in that assembly.