In-Depth
Build a SharePoint Web Part
Create a customizable Suntimes calculator using the free, built-in SharePoint functionality that lets users supply their own data to a custom Web Part.
Technology Toolbox: VB.NET, ASP.NET, Windows Server 2003, Windows SharePoint Services or SharePoint Portal Server 2003
One of SharePoint Portal Server's selling points is that it provides broad customization at all levels, from a corporation's home page down to a single user's personal page. Without having to write code, users can assemble content, design their pages, and rearrange sections to reflect their tasks, role, personality, and location. Personalization is especially effective in SharePoint Web Parts, which are small pluggable units that can generate individual views of data, lists, and alerts. Personalization is more than the option to show, hide, or collapse a canned Web Part; it's also the ability to set individual values and parameters, save them, and restore them at the next logon.
I'll show you how easy it is to piggyback on the free, built-in SharePoint functionality that lets users supply their own data to a custom Web Part. The sample project included with this article calculates the sunrise and sunset times based on the longitude, latitude, and time zone a user provides. When the Web Part is installed and configured on the page, it displays the sun times for the current day and location (see Figure 1).
The interface displays the tool pane when users modify a Web Part (see Figure 2). This is a built-in utility section where administrators and regular users (if they're granted sufficient permissions) can provide parameters, defaults, and other settings for the components that make up the page.
I'll also show you how to enable customization so SharePoint maintains a user's settings in his or her personal storage area. After I discuss the basic details about building the Web Part, I'll show you how to deploy the package so any user can drop it on a personal page.
Note that the sample code includes advanced formulas and algorithms that generate the sun times, but I don't discuss those functions here. The complex code comes from the National Oceanic and Atmospheric Administration (NOAA) Surface Radiation Research Branch, a U.S. government agency, and is available on the NOAA Web site and on GotDotNet (see Additional Resources). For the limited purposes here, I've stripped the sun times code to its bare essentials and assembled it into two classes: calculations and SunRoutines. Both are included in the downloadable project. You treat these classes as black boxes into which you push parameters and get back the values to display:
sunrout = New SunRoutines
sr = New calculations
sr = sunrout.GetSunriseSunset _
(location, latitude, longitude, _
timezone, IIf(dst = True, 1, 0), _
zenithvalue)
SharePoint Web Parts are ASP.NET server controls with some added features that make them work well in the SharePoint context. Designing these controls by hand can be tricky, but Visual Studio 2005 promises to catch up to the Web Part technology by including a WYSIWYG designer. For the time being, you can get by nicely with the available tools and documentation. Microsoft provides a downloadable Web Part library template that gets you started in Visual Studio .NET 2003 and an SDK with samples and an API reference.
Make Microsoft.SharePoint.dll Available
A Web Part inherits from Microsoft.SharePoint.WebPartPages.WebPart. Therefore, you need to fetch a copy of Microsoft.SharePoint.dll from your SharePoint server and make it available to VS.NET. Add a reference to the SharePoint DLL in your project and import these namespaces: Microsoft.SharePoint, Microsoft.SharePoint.Utilities, and Microsoft.SharePoint.WebPartPages.
You'll see that I use a class called suntimes in the sample project. Dig through the well-decorated code to find the class declaration:
<DefaultProperty("Text"), _
ToolboxData("<{0}:suntimes" & _
" runat=server>" & _
"</{0}:suntimes>"), _
XmlRoot(Namespace:="suntimes")> _
Public Class suntimes
Inherits Microsoft.SharePoint. _
WebPartPages.WebPart
You must override two subroutines to build your own Web Part. The first, CreateChildControls, is where you retrieve data and instantiate, configure, and assemble screen objects such as ASP.NET Label and Image controls. For example, this snippet creates a new instance of the Label control, assigns a default location value to it, sets the CssClass, then builds a tooltip:
lblLocation = New Label
lblLocation.Text = sr.location
lblLocation.CssClass = _
"ms-announcementtitle"
lblLocation.ToolTip = _
"Latitude: " & _
sr.latitude.ToString & _
" / Longitude: " & _
sr.longitude.ToString
Look at lblLocation (Toronto) at run time as the mouse passes over the text (see Figure 3). When you design a Web Part, remember to assign the stylesheet class names used elsewhere in the SharePoint page. For example, when you use the ms-announcementtitle style, your Web part inherits the appearance automatically that the user or administrator has chosen. This is another example of where SharePoint lets you adopt its style and functionality for free.
Handling images in the CreateChildControls subroutine in a Web Part is easy because the Microsoft designers relieve you of two potentially messy issues: where to install the bitmaps and how to reference them in code. SharePoint stores most content in a database, so you can't rely on relative paths the way you might in a regular Web application.
To reference the image at run time, use the ClassResourcePath property to return the path where the image was installed, then add on the name of the bitmap:
imgSunrise = New Image
imgSunrise.ImageUrl = _
MyBase.ClassResourcePath & _
"/sunrise.gif"
imgSunrise.ToolTip = "Sunrise"
The physical storage location in SharePoint can be obscure until you analyze it. For example, the images on my system are in Program Files\Common Files\Microsoft Shared\web server extensions\wpresources\suntimes\1.0.0.0_ _2fbbc3d44cff9dc2. The wpresources folder is the standard root for added Web Parts, and the suntimes folder matches the Web Part's name. The final folder name concatenates the Web Part assembly's version number with the public key token (2fbbc3d44cff9dc2, in this case) that gives the assembly a strong name. (I'll talk more about strong names later when I cover building and deployment.)
Override RenderWebPart
The second subroutine that you must override is RenderWebPart. It takes an HtmlTextWriter object as a parameter. The HtmlTextWriter's Write method pushes out the HTML code at run time. Use the Write method directly to emit simple HTML, such as tags for a table, row, and cell. For more complex ASP.NET components, call the control's RenderControl method, which adds the control's markup to the output stream:
output.Write(" <SPAN class=''>")
lblLocation.RenderControl(output)
output.Write("</SPAN></td></tr>")
The CreateChildControls and RenderWebPart subroutines render the Web Part to the main portion of the page, but you need a way for the end user to personalize the data. Fortunately, there's almost nothing to do apart from some property "decoration." In another example of providing free functionality, SharePoint's designers pick up the property declarations from your code and use them in the tool pane. Look at the location property definition that holds a string such as Toronto:
<Browsable(True), _
Category("Sunrise/Set Config"), _
DefaultValue(_dfLoc), _
WebPartStorage(Storage.Personal), _
FriendlyName("Location"), _
Description("Enter the name" & _
" of the city.")> _
Property location() As String
Get
Return _location
End Get
Set(ByVal Value As String)
If IsNothing(Value) Or _
Value = "" Then
Throw New _
WebPartPageUserException _
("Please enter a " & _
"location name.")
End If
_location = Value
End Set
End Property
You allow a property definition to appear as an editable textbox in the tool pane by marking it as Browsable. The Category decoration mandates the section of the tool pane in which this textbox appears. The default categories include Appearance, Layout, and Advanced, but add your own called Sunrise/Set Config.
Continuing with the tool pane settings, DefaultValue sets the starting value before customization. WebPartStorage tells SharePoint where these values are saved for future use. In this case, the storage value is Storage.Personal, a customization level that makes this data individual to the user. FriendlyName becomes the label text above the control, and Description generates the tooltip over FriendlyName to guide users as to a valid value to enter.
SharePoint determines the type of HTML control to render for data input by looking at the property definition. A string becomes a textbox, an enum structure creates a dropdown list, and a Boolean renders as a checkbox.
When you validate data in the Set accessor, your error handling is hooked automatically into SharePoint's functions. For example, if the data is bad, you send the page an error message by throwing a WebPartPageUserException exception with the message string as a parameter. SharePoint catches this exception for you and displays a general message at the top of the tool pane and your specific text at the scene of the validation failure (see Figure 4).
Make Custom Settings Available
Make custom settings available in the tool pane by overriding the GetToolParts function. Create and add your custom ToolPart to the array of ToolParts:
Public Overrides _
Function GetToolParts() _
As ToolPart()
Dim toolPane As ToolPane
Dim toolParts(2) As ToolPart
Dim wptp As WebPartToolPart = _
New WebPartToolPart
Dim custom As _
CustomPropertyToolPart = _
New CustomPropertyToolPart
custom.Expand("Sunrise/Set Config")
toolParts(1) = wptp
toolParts(0) = custom
viewstate("sr") = Nothing
Return toolParts
End Function
SharePoint pushes custom tool parts to the bottom of the tool pane by default. You can move your controls to the top with a little sleight of code. Assign the default tool part to a lower array index, and reserve toolParts(0) for your custom creation. The zero item appears at the top of the tool pane.
As I showed you earlier, the installation folder for resources is made from the assembly name, version number, and public key token. This reflects the .NET reality that the Global Assembly Cache (GAC) can store multiple versions of the same software or Web Partdifferentiated only by the strong name.
Give your Web Part a strong name by creating a key pair using the command-line utility sn.exe. Then reference the generated file as the AssemblyKeyFileAttribute value in your project's AssemblyInfo.vb file:
<Assembly: AssemblyKeyFileAttribute _
("../../suntimes.snk")>
You can provide a custom icon such as the yellow sun to help users locate your Web Part in the Virtual Server Gallery (see Figure 5). Create two graphics, one 16 pixels square and the other 32 pixels square. You must reference these icons in the manifest and the Web Part description file.
The Web Part description file (in this case, suntimes.dwp) holds vital information about the resources used in the Web Part, what needs to be deployed, and where to find it. The entry in the definition file for the icons uses two nodes that include a SharePoint token called _WPR_:
<PartImageSmall>_WPR_/suntimes16.png
</PartImageSmall>
<PartImageLarge>_WPR_/suntimes32png
</PartImageLarge>
When SharePoint parses the URL to display the icons, it converts the _WPR_ token to the class resource path.
Information in the DWP file helps users select the Web Part from a list and add it to the page. The Title element holds the text for the part's title on the page and within the Gallery. Description creates the tooltip text to show when users pass the mouse over the title in the tool pane (see Figure 5). The Assembly element, which doesn't appear on the screen, describes the Web Part assembly in intricate detail, down to the version, culture, and PublicKeyToken values.
Discovering the PublicKeyToken for the assembly is easy with the right tool. Lutz Roeder's .NET Reflector shows the "real" name of the assembly. Enter it as the Assembly value. The TypeName element contains the namespace and class names:
<?xml version="1.0" encoding="utf-8"?>
<WebPart xmlns="http://schemas.
microsoft.com/WebPart/v2" >
<Title>Sunrise/Sunset Times</Title>
<Description>Shows the sunrise and
sunset times for a given location and
time zone.</Description>
<Assembly>suntimes,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=2fbbc3d44cff9dc2
</Assembly>
<TypeName>suntimes.suntimes
</TypeName>
<PartImageSmall>_WPR_/suntimes16.png
</PartImageSmall>
<PartImageLarge>_WPR_/suntimes32.png
</PartImageLarge>
</WebPart>
Include Images as Class Resources
Make sure the images are installed by including them as class resources in manifest.xml:
<WebPartManifest
xmlns="http://schemas.microsoft.com
/WebPart/v2/Manifest">
<Assemblies>
<Assembly FileName="suntimes.dll">
<ClassResources>
<ClassResource
FileName="sunrise.gif"/>
<ClassResource
FileName="sunset.gif"/>
<ClassResource
FileName="suntimes16.png"/>
<ClassResource
FileName="suntimes32.png"/>
</ClassResources>
<SafeControls>
<SafeControl
Namespace="suntimes"
TypeName="*"
/>
</SafeControls>
</Assembly>
</Assemblies>
<DwpFiles>
<DwpFile FileName="suntimes.dwp"/>
</DwpFiles>
</WebPartManifest>
The manifest stores settings for the distribution and deployment of the Web Part. The ClassResource element shows that four images belong to this package and need to be deployed with it. The SafeControl element is important for security because the values for the Namespace and TypeName attributes assure the host system that any class in the suntimes namespace is okay to use.
Once the strongly named Web Part compiles and includes references to the additional files, you're ready to package it for deployment. The Cab file format is a convenient and efficient way to distribute Web Parts because SharePoint's utilities can uncompress, unbundle, and deploy Cabs readily. You can add a Cab project to your solution in Visual Studio by looking under the Setup and Deployment Projects category. Configure the Cab project to include the primary output and the content files from your Web Part project. Tip: Create a shared folder on the SharePoint test server and set that as the destination for the generated Cab file. You'll avoid manual file copying during the iterative deploying/testing/fixing cycle by dropping the fresh build directly into a deployment folder.
To deploy the Web Part, make sure you're logged on to the Windows 2003 Server machine with administrator privileges. The SharePoint command-line administration tool, stsadm.exe, handles the deployment. The utility is usually found in Program Files\Common Files\Microsoft Shared\web server extensions\60\BIN\. You'll save keystrokes by putting the tool's location in your path and creating a batch file.
The deployment command for the sun times package takes four switches:
stsadm -o addwppack -globalinstall _
-force -filename suntimescab.CAB
The -o switch announces that an operation is comingnamely, add a Web Part package (addwppack). The -globalinstall switch instructs the tool to put this Web Part into the GAC to make it trusted. The third switch, -force, overwrites any existing Web Part with this name. The final switch provides the name of the file to install: suntimescab.cab.
Finally, you reach the goal: adding the Sunrise/Sunset Times part to a SharePoint page. The Gallery appears when you click on Modify My Page | Add Web Parts | Browse. If all is well, the Virtual Server Gallery includes Sunrise/Sunset Times in its list. You can drag the Web Part from the Gallery and drop it onto a zone (see Figure 6). All that's left for users to do is to open the tool pane and enter their longitude, latitude (they can ask city hall), and time-zone offset.
You've seen that you can tap into significant out-of-the-box SharePoint functionality with little effort. SharePoint assembles Web Parts into lists, builds HTML controls in the tool pane based on the property type, adds tooltips, and generates drag-and-drop capabilities. The system tracks deployed resources such as images and tells your code where they are. When users personalize the Web Part, SharePoint stores their updates and ensures that it fits the site's "look" by providing inheritable stylesheet classes. Get started with the downloadable code now so you can have your own Web Part online before the sun rises again.