Microsoft Windows SharePoint Services

 

This chapter is taken from Microsoft Windows SharePoint Services Inside Out published by Microsoft Press; ISBN 0735621713; copyright Microsoft Press 2005; all rights reserved. The author, Jim Buyens, has written more than 10 books on Web-based development, including Microsoft Office FrontPage 2003 Inside Out from Microsoft Press. Jim has 20 years of experience with computer networking technologies and is a Microsoft Most Valuable Professional who contributes extensively to the Microsoft Office FrontPage online communities.

No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

Chapter 19: Beginning Web Part Development

Contents

Configuring Your Development Environment
How Web Parts Work
Starting a New Web Part Project
Writing Web Part Output
Adding Layout Controls and Content
Manipulating SharePoint Objects
Using the ASP.NET Event Model
Exposing Custom Properties
Using Web Part Tool Parts
Providing a Design Time HTML Provider
Assigning a Strong Name
Deploying Custom Web Parts
In Summary

With the flexibility of powerful prewritten Web Parts, Web Part Pages, custom lists and libraries, browser-based editing, FrontPage-based editing, Data Sources, Data Views, Web Part connections, and connectivity to Microsoft Office applications, it's amazing how much you can do with Microsoft Windows SharePoint Services without programming. Inevitably, however, no tool—or set of tools—can do everything. And with software, that's the time to think about writing your own code.

In a SharePoint environment, writing your own code usually means writing Web Parts. Web Parts integrate smoothly with the rest of your SharePoint site, leveraging its existing appearance, organization, security, and data management. What's more, Web Parts are reusable. You can write them once and use them in as many pages as you like.

Of course, these advantages come at a price. Web Parts work differently than ordinary Microsoft ASP.NET pages do, and much more differently than legacy ASP pages. As a result, developing and deploying a Web Part requires a different mind-set and a somewhat different tool set than does developing other kinds of server-based Web components. With that in mind, this chapter explains the essence of how Web Parts work and what software you need to develop them. Chapters 20 and 21 will provide step-by-step instructions for creating some simple but useful Web Parts.

The purpose of these chapters is to introduce Web Part programming. They assume you already have some experience with Microsoft .NET programming, and with Web-based programming in general. The examples are in Microsoft C, but you could use Microsoft Visual Basic .NET just as effectively.

Configuring Your Development Environment

Web Parts run only within the environment of Windows SharePoint Services, which, in turn, requires Microsoft Windows Server 2003 or later. As a result, you'll need a copy of Windows Server 2003. If possible, you should have your own server because:

  • Software development by its very nature leads to frequent Microsoft Internet Information Services (IIS) resets and occasional system reboots.
  • Interactive debugging works best on the local machine, and can monopolize resources.
  • To get your application working (or figure out why it isn't), you'll need authority to inspect or adjust any aspect of system configuration.

You can run Windows Server 2003 in any of these modes:

  • As your primary workstation operating system   This option uses the least hardware, but exposes your day-to-day work environment to changes or crashes caused by unfinished (and therefore unreliable) software. In addition, you may encounter issues running desktop software designed primarily for Microsoft Windows XP.
  • On its own computer   This option isolates your daily working environment from your development activities, but it does require another piece of hardware.
  • As a virtual machine under Microsoft Virtual PC   This option saves you the expense of buying a new computer, but it's not free. You still have to buy Microsoft Virtual PC and, in all probability, some additional memory and disk space for the PC that will run it. A major advantage, however, is the ease of saving and restoring system images. If you find that some approach or some experiment isn't working out, you can revert to an earlier system image.

To create, compile, and test the code for Web Parts, you'll need a copy of Visual Studio .NET. Any version will do, including the stand-alone products Visual C .NET Standard Edition and Visual Basic NET Standard Edition.

Microsoft Developer Network (MSDN) subscriptions come with licenses to download, install, and run Visual Studio .NET, Virtual PC, Windows Server 2003, Microsoft SQL Server, and most other Microsoft products for development use only. MSDN Universal, the top offering, includes all Microsoft Office programs and SharePoint Portal Server. For more information about this option, see Microsoft Developer Products.

How Web Parts Work

In ASP.NET terminology, a server control is a software component that runs on the Web server as part of one or more ASP.NET Web pages. This provides a way of breaking complex Web pages into manageable pieces, and of using the same component in multiple pages. There are two kinds of ASP.NET server controls: user and custom.

  • User Controls   These controls consist of two parts:

    • A file that has an .ascx file name extension, and that contains sample HTML.
    • The program code that executes on the Web server. This code, plus the code for all other ASP.NET pages and user controls in the same application, is usually compiled into a single DLL that resides in the application's bin folder. However, it can also reside in source form, within the .ascx file.

    Most developers find user controls fairly easy to create. This is because the developer (or even a Web designer) can use a visual designer to create the sample HTML, and because programming a user control is very much like programming an ordinary ASP.NET page.

    User controls, however, can be difficult to deploy widely. When a change occurs, someone must:

    1. Identify each Web site that uses the control.
    2. Install the new .ascx and source code files in each Web site.
    3. Recompile all the source code in each Web site.
    4. Copy the revised .ascx file and the recompiled code to each production Web site.

    If Web Parts were user controls, deploying a new Web Part (or upgrading one) would require recompiling and reinstalling the program code for every SharePoint site that uses the Web Part. That's why Web Parts aren't user controls.

  • Custom Controls   These controls consist entirely of program code. There's no HTML template like the .ascx file for a user control, and consequently no way of using a WYSIWYG editor to design its HTML. A programmer must write code that emits each scrap of HTML that the control needs in order to display output.

    The advantage of custom controls lies in deployment. Each custom control (or, if you choose, each logical group of custom controls) has its own DLL, and at your option you can install this once per physical server or once per virtual Web server. This is the model that Web Parts use. All Web Parts are, in fact, ASP.NET custom controls.

In practice, laying out page elements with no WYSIWYG editor and writing program code that emits HTML aren't the grueling tasks you might expect. The reason is that the output of most Web Parts is fairly simple. Many page elements—such as the top navigation bar, the page banner, any toolbars, and any link areas—are part of the Web Part Page or of other Web Parts. Any Web Parts you create need only display their specific data, and they inherit styles from the site's theme.

Windows SharePoint Services provides a base class for creating Web Parts, namely Microsoft.SharePoint.WebPartPages.WebPart*.* This class provides a base upon which you can write any type of Web Part you like. To inherit from this class (that is, to use it as a base), you code the following statement in the source code for your Web Part:

class WebPart1 : Microsoft.SharePoint.WebPartPages.WebPart 
{
// Your custom code goes here. 
}

In addition, virtually all Web Parts override two methods in the WebPart class:

  • CreateChildControls   The WebPart class calls this method to create child server controls that the Web Part will later convert to HTML.
  • RenderWebPart   The WebPart class calls this method to render (that is, create) the HTML that the Web Part will display.

Note   If you've ever written ASP.NET custom controls that aren't Web Parts, you're probably accustomed to overriding the Render method rather than the RenderWebPart method. In a Web Part, however, the Render method creates only the chrome (the Web Part's title bar and border, for example). The RenderWebPart method creates the HTML that appears in the body of the Web Part.

The reason for overriding (that is, superseding) these methods is that the versions in the WebPart class essentially do nothing. Overriding them means that at the proper time, the WebPart class will call custom methods you provide rather than its own do-nothing methods. Adding these two overrides to the previous code gives the Web Part this structure:

class WebPart1 : Microsoft.SharePoint.WebPartPages.WebPart 
{ 
//  Global declarations go here.
protected override void CreateChildControls ()
    {
//      Code to create a list of Web or HTML server 
//      controls goes here
    }
protected override void RenderWebPart(HtmlTextWriter output) 
    {
//      Code to render the list of Web or HTML server 
//      controls goes here
    }
}

For more information about overriding the CreateChildControls method, see Adding Layout Controls and Content.

For more information about overriding the RenderWebPart method, see Writing Web Part Output.

If you've written conventional ASP.NET pages or ASP.NET user controls, you probably made extensive use of the Page_Load event. A similar event occurs for custom controls, but most Web Parts never bother detecting it. There are at least two reasons for this:

  • Page_Load normally fires when ASP.NET finishes loading the page's server controls into memory. In a Web Part, however, ASP.NET doesn't load the server controls; your own CreateChildControls method does that. So, you may as well put your code in the CreateChildControls method, or call it from within that method.

  • Within a Page_Load event handler, programmers normally use the IsPostBack property to differentiate between the initial display of a page and a subsequent submission. But in the case of Web Parts, a postback also occurs when a team member uses a browser to add, remove, or reconfigure any Web Part on the page.

    This makes sense if you stop and think about it. There are many times—such as when you use a browser to add a Web Part to a page—when a round trip to the server clearly occurs. However, these aren't normal form submissions, and you shouldn't process any data that form fields might contain.

So, if you're not going to use Page_Load to initialize the display, and you're not going to use it for form submissions, you're probably not going to use it much at all.

As in conventional ASP.NET pages, most Web server controls have onServerClick or onServerChange events that can trigger event handlers in a Web Part. This is the normal way of detecting actual form submissions.

For more information about using onServerClick and onServerChange events in a Web Part, see Using the ASP.NET Event Model.

Starting a New Web Part Project

Before starting to create your first Web Part, you need to have Windows SharePoint Services up and running, and any version of Visual Studio .NET installed on the computer you plan to use for coding and compiling.

With those items in place, you're ready to install the Web Part templates For Visual Studio .NET. This is something you need to do only once. Here's the procedure:

  1. If you're not going to run Visual Studio on the SharePoint server, copy the Microsoft.SharePoint.dll file from the server to the Visual Studio machine. By default, this file resides at:

    C:\Program Files\Common Files\Microsoft Shared\web server extensions\60\ISAPI

    You can copy this file to any folder you like on the Visual Studio machine; just remember its location and don't delete it by accident.

  2. On the machine where Visual Studio is installed, browse https://www.microsoft.com/technet/downloads/sharepnt.mspx.

  3. When the Downloads for SharePoint Products and Technologies page appears, click the hyperlink titled SharePoint Products And Technologies Templates: Web Part Templates For Visual Studio .NET.

  4. When the Download Details page appears, click the Download button and save the resulting file (WebPartTemplatesforVSNetSample2.exe) to a temporary location.

  5. Run the file you downloaded in step 4. When the WinZip Self-Extractor dialog box appears, choose a folder for the unzipped setup files and then click Unzip.

  6. Open the folder you specified in step 5 and run the setup.exe program.

  7. Click Next on the opening page of the setup wizard, and then I Agree and Next on the License Agreement page.

  8. On the third wizard page, select the check box for each set of templates you want to install. The choices are Visual C and Visual Basic .NET. The examples in this book are all in C, but feel free to install both.

  9. If the wizard page shown in Figure 19-1 appears, enter the folder location where you saved the Microsoft.SharePoint.dll file you copied in step 1.

  10. Click Next and Finish to perform the installation.

If you install the Web Part Templates for Visual Studio .NET on a machine not running Windows SharePoint Services, you'll need to supply a local copy of Microsoft.SharePoint.dll and provide its location on this wizard page

Figure 19-1. If you install the Web Part Templates for Visual Studio .NET on a machine not running Windows SharePoint Services, you'll need to supply a local copy of Microsoft.SharePoint.dll and provide its location on this wizard page.

To actually start programming a Web Part, proceed as follows.

  1. Start Visual Studio, choose New from the File menu, and then choose Project.

  2. When the New Project dialog box shown in Figure 19-2 appears, apply the following settings and then click OK:

    • Project Types   Select either Visual Basic Projects or Visual C Projects. This presumes, of course, that you installed the corresponding templates in the previous procedure. The examples in this book are all in C.
    • Templates   Choose Web Part Library.
    • Name   Specify the name of the Visual Studio project. By default, this will also be the name of the DLL that deploys your Web Part. Visual Studio will also create a solution having this name.
    • Location   Specify a folder where the Visual Studio project and solution will reside.

    The Web Part library template initializes a project for creating Web Parts

    Figure 19-2. The Web Part library template initializes a project for creating Web Parts.

  3. Visual Studio will create the new project and open the class file for a Web Part named WebPart1. Figure 19-3 illustrates this result.

    This new Web Part project is ready to receive custom code

    Figure 19-3. This new Web Part project is ready to receive custom code.

  4. Unless you want your Web Part to be named WebPart1:

    1. Choose Find And Replace from the Edit menu, and then choose Replace.

    2. When the Replace dialog box appears, set Find What to WebPart1, Replace With to the name you want, and then click Replace All.

    3. Click the close box in the Replace dialog box, and then in the WebPart1.cs file. When Visual Studio prompts Save Changes To The Following Items?, click Yes.

    4. Right-click the WebPart1.cs file in Solution Explorer, choose Rename from the shortcut menu, and change the file name base to the name you assigned in step 4.2.

      Tip   If the Solution Explorer window isn't visible, press CTRL+ALT+L or choose Solution Explorer from the View menu.

Writing Web Part Output

For an ordinary ASP.NET page or user control, the first step after creating a new file is to design the HTML. This is also true for ASP.NET custom controls (and consequently for Web Parts) but, because there's no text file that contains "raw" HTML, you need to approach this task differently.

As you no doubt recall, every Web Part that creates output contains a method declaration like this:

protected override void RenderWebPart(HtmlTextWriter output)
{
}

ASP.NET runs this function automatically after all initialization functions, event handlers, and child functions have finished—in short, when all other processing is complete. To actually emit HTML, you have a choice of two approaches:

  • You can call the Write method of the HtmlTextWriter object named output. (Note that the RenderWebPart method receives a pointer to this object as an argument.) For example, to write a paragraph that displays the value of a variable named strMsg, you would code:

    output.Write("<p>" + SPEncode.HtmlEncode(strMsg) + "</p>");
    

    SPEncode.HtmlEncode is a method that converts reserved HTML characters to character entity references. For example, it converts < to &lt; and > to &gt;.

  • You can call the RenderChildren method, specifying the HtmlTextWriter object named output as a parameter. Here's an example:

    RenderChildren(output);
    

To understand the RenderChildren method, you should know that every ASP.NET page, user control, and custom control has a Controls collection. This collection contains an object for each element the page or control will display. When you're working with ASP.NET pages or user controls, ASP.NET loads the Controls collection from the .aspx or .ascx file as follows:

  • Each tag you code runat="server" creates a corresponding object in the Controls collection.
  • Any content that appears between tags coded runat="server" appears in the Controls collection as a single System.Web.UI.LiteralControl object.

Because custom controls (and therefore Web Parts) have no .aspx or .ascx file, the Controls collection is initially empty. You can, however, write program code that adds any controls you want to the Controls collection. Here's an example:

HtmlGenericControl prgMsg;             // Declare variable. 
prgMsg = new HtmlGenericControl("p");  // Create object. 
prgMsg.InnerText = strMsg;             // Set value inside <p>
                                       // and </p>. 
Controls.Add(prgMsg);                  // Add to Controls 
                                       // collection.

A single call to the RenderChildren method will then tell each control, in order, to emit its HTML. If you use code such as the above to create five paragraph controls, RenderChildren would write five sets of <p> and </p> tags, each with the content you assigned.

The choice between using output.Write and RenderChildren is entirely yours. The output.Write method is easier to see and understand. Loading up the Controls collection and calling RenderChildren is more abstract, but it helps modularize your program and it guards against invalid HTML.

Although there's nothing wrong with output.Write, the examples in this book will use the RenderChildren method exclusively.

Adding Layout Controls and Content

ASP.NET provides two sets of objects you can add to a Controls collection. They are:

  • System.Web.UI.HtmlControls   These controls correspond very closely to standard HTML elements. For a complete list, see System.Web.UI.HtmlControls.

    To use these controls, the source code for your Web Part should contain this statement:

    using System.Web.UI.HtmlControls;
    

    Otherwise, you'll need to type the entire namespace every time you refer to one of its class names.

  • System.Web.UI.WebControls   Controls in this group are either:

    • Enhanced versions of HTML server controls. Unlike the HtmlSelect control, for example, the ListBox Web server control can trigger immediate postbacks.
    • Entirely new elements, such as a calendar, an ad rotator, and the ubiquitous DataGrid control.

    For a list of these controls, see System.Web.UI.WebControls.

    To use these controls, the source code for your Web Part should contain this statement:

    using System.Web.UI.WebControls;
    

The preceding section already showed some example code for creating a paragraph tag and adding text to it. Here it is again.

HtmlGenericControl prgMsg;
prgMsg = new HtmlGenericControl("p");
prgMsg.InnerText = strMsg;
Controls.Add(prgMsg);

In fact, however, not all this code is likely to appear together in one block. The second and fourth statements must appear within the CreateChildControls method, as shown below:

protected override void CreateChildControls ()
   {
prgMsg = new HtmlGenericControl("p");
Controls.Add(prgMsg);     
   }

The second statement, however, could easily reside in the method that determines the value of the strMsg variable. Here's an example:

HtmlGenericControl prgMsg; 
 
public void MsgLoad(object sender, EventArgs e) 
{ 
    string strMsg; 
    strMsg = "Help! I'm a prisoner in a Web Part!"; 
    EnsureChildControls(); 
    prgMsg.InnerText = strMsg; 
} 
protected override void CreateChildControls () 
{ 
    prgMsg = new HtmlGenericControl("p"); 
    prgMsg.Load += new EventHandler(MsgLoad); 
    Controls.Add(prgMsg); 
}

In this code:

  • The statement on line 13 establishes MsgLoad as an onLoad event handler for the prgMsg object. This means that the MsgLoad method on line 3 will run as soon as the prgMsg object finishes loading.
  • The EnsureChildControls method on line 7 ensures that the CreateChildControls method has finished executing. If not, it waits for that method to complete. This avoids the embarrassing moments that occur when a method tries to manipulate an object that CreateChildControls hasn't created yet.
  • The assignment statement on line 8 stores a value into the paragraph control created on line 12.
  • The declaration of the prgMsg variable appears on line 1, which is outside both the MsgLoad method and the CreateChildControls method. This makes the prgMsg available within both of those methods.

This, by the way, plus the Web Part templates for Visual Studio .NET, is just about all the code you need to write an elementary Web Part. A Visual Studio project using this code appears in the \WebParts\proseware folder of the companion CD, and a screen shot appears in Figure 19-4.

This is a very simple Web Part, and it required very little code

Figure 19-4. This is a very simple Web Part, and it required very little code.

Manipulating SharePoint Objects

Windows SharePoint Services provides a rich collection of objects for working with sites, lists, permissions, and other administrative objects. All these objects reside within a namespace named, logically enough, SharePoint. Its major classes include:

  • SharePoint.SPSite   Represents a SharePoint site collection. Its properties and methods provide access to the collection's subsites, templates, cross-site groups, and so forth.

    Remember: an SPSite object doesn't represent a site. Its properties and methods pertain to an entire site collection, and not to any one Web site.

  • SharePoint SPWeb   Represents an individual SharePoint site: either a top-level Web site or a subsite. It provides access to all of the site's lists, files, folders, Web Parts, and other objects.

  • SharePoint.SPList   Represents a SharePoint list. The term list, in this context, is very broad. It includes not only generic lists, but also surveys, discussion boards, document libraries, picture libraries, and form libraries.

For a complete listing and description of the objects in the SharePoint namespace, see Microsoft.SharePoint Namespace.

The statement below creates an SPWeb object named spwCurr that describes the current SharePoint Web site. In other words, it describes the site that contains the page that displayed the Web Part.

SPWeb spwCurr = SPControl.GetContextWeb(Context);

The next statement creates an SPSite object named spsColl that describes the site collection that contains the current site.

SPSite spsColl = SPControl.GetContextSite(Context);

Once you have these objects, you can retrieve more information about the site or its collection by using their properties and methods. For example, after you create an SPWeb object named spwCurr as described above:

  • spwCurr.CurrentUser.LoginName   Returns the current team member's login name, such as interlacken\karen.M
  • spwCurr.CurrentUser.Name   Returns the current team member's personal name, such as Karen Archer.
  • spwCurr.Name   Gets or sets the name of the current site.
  • spwCurr.Lists   Returns a collection of SPList objects, one for each list in the site.
  • spwCurr.Delete()   Deletes the current site.

In most cases, if a property is editable, your code can simply store a value into it. Editable, in this sense, means that Windows SharePoint Services permits direct updates to a field, and that the current user has permission to perform the operation.

To enumerate a collection, code a foreach loop like the one below:

(SPList splCurr in spwCurr.Lists) {
// splCurr will point to a different list during each iteration 
}

In addition, you can index into lists using either numbers or names. The following statement, for example, creates an SPList object named splNrTwo that points to the second list in the spwCurr.Lists collection:

SPList splNrTwo = spwCurr.Lists[1];

And this statement creates an SPList object that points to a Shared Documents library:

SPList splSharedDocs = spwCurr.Lists["Shared Documents"];

To add objects to and remove them from SharePoint collections, you use Add and Delete methods, just as you do with most other .NET collections. The following statement, for example, creates a new Contacts list named Swamp Dwellers. The second parameter supplies the list description:

spwCurr.Lists.Add("Swamp Dwellers",
"Ducks, Frogs, Gators, and other creepy critters", 
SPListTemplateType.Contacts);

Using the ASP.NET Event Model

Web Parts experience the same lifecycle events as ordinary Web pages: Init, Load, Data-Binding, PreRender, and Unload. To capture these, add a method like the following to the class for your Web Part:

Protected override void OnLoad(EventArgs e) 
{
// Your code goes here
base.OnLoad(e); 
}

This example illustrates the code for the Load event. To capture other life cycle events, change the word *Load—*in two places—to Init, DataBinding, PreRender, or Unload.

To capture button clicks, drop-down menu changes, and other form events, you must create the control, add an event hander to it, and then code the event handler. The following code, for example, creates a DropDownList control, adds an event handler named Priority_Change for the SelectedIndexChanged event, and then forces the form to autosubmit whenever the team member changes the current selection.

lstPriority = new DropDownList();
lstPriority.SelectedIndexChanged
    += new EventHandler(Priority_Change);
lstPriority.AutoPostBack = true;

Note the += operator in the second statement. This appends the new event handler without discarding any others for the same event. The code for the event handler itself appears below.

private void Priority_Change(object sender, EventArgs e) 
{
// Your code goes here. 
}

A Visual Studio project illustrating these techniques appears in the WebParts\tailspintoys folder of the companion CD, and a screen shot appears in Figure 19-5.

This Web Part traces and displays its lifecycle steps. The current display reflects four submissions

Figure 19-5. This Web Part traces and displays its lifecycle steps. The current display reflects four submissions.

This figure illustrates four executions of the Web Part Page, and therefore of the Web Part.

  • The Load and PreRender event handlers display simple messages, and fire for each execution.

  • The following code creates the drop-down list:

    lstPriority = new DropDownList();
    lstPriority.SelectedIndexChanged
        += new EventHandler(Priority_Change);
    lstPriority.AutoPostBack = true;
    

    And this code populates the list items:

    (lstPriority.Items.Count < 1) 
    {
        lstPriority.Items.Add(new ListItem("High","1"));
        lstPriority.Items.Add(new ListItem("Medium","2"));
        lstPriority.Items.Add(new ListItem("Low","3"));
        litMsgs.Text += "<br>"
           + DateTime.Now.ToLongTimeString()
           + " Priority List Loaded."; 
    }
    

    The message Priority List Loaded appears only once in Figure 19-5 because the ASP.NET ViewState mechanism persists the items (and the current selection) from one execution to another.

    The messages Priority Is Now 2 and Priority Is Now 3 appear because the team member changed the selection in the drop-down list box, and this caused an autopostback.

  • The message Submit Button Clicked appears because the team member clicked the Submit button. The following code creates this button and specifies a Click event handler named Submit_Click.

    btnSubmit = new Button();
    btnSubmit.Text = "Submit";
    btnSubmit.Click += new EventHandler (Submit_Click);
    

    Here's the code for the event handler:

    Private void Submit_Click(object sender, EventArgs e) 
    {
        EnsureChildControls();
        litMsgs.Text += "<br>"
              + DateTime.Now.ToLongTimeString()
              + " Submit Button Clicked."; 
    }
    

As in all ASP.NET pages, a single HTML form surrounds the content of each Web Part Page. Therefore, you needn't ever (and shouldn't ever) add your own <form> tags or HtmlForm objects to a Web Part. The Web Part Page will provide these.

When a Web Part Page displays several Web Parts, they all execute every time the Web page makes a round trip to the server. For example, your Web Part will execute:

  • Every time the team member clicks the browser's Refresh button.
  • Every time the team member clicks a Submit button or otherwise creates a postback from another Web Part.
  • Every time the team members use browser-based design features such as:
    • Switching from shared view to personal view.
    • Entering, using, or exiting browser-based Design mode.
    • Displaying the Add Web Parts task pane.
    • Scrolling through multiple pages in a Web Part gallery.
    • Modifying a Web Part.

As a result, any event handlers in your Web Part that book orders, adjust account balances, or perform any other kinds of updates should only react to events that come from elements that you know reside in your Web Part, and not to general, page-wide events like Page_Load.

Exposing Custom Properties

Many Web Parts expose properties that team members can change through the Modify Web Part task pane in the browser, or through the Web Part Properties dialog box in Microsoft Office FrontPage. The Text property in Figure 19-6 provides an example. Windows SharePoint Services calls these custom properties.

The input field titled Text is a SharePoint custom property. Windows SharePoint Services does most of the work in displaying and saving such values

Figure 19-6. The input field titled Text is a SharePoint custom property. Windows SharePoint Services does most of the work in displaying and saving such values.

The code that appears below creates a custom property named Text. You put this inside the class definition for your Web Part, but not inside any method. The Web Part templates for Visual Studio .NET provide a version of this code in every new Web Part class file.

private const string defaultText = "";
private string text = defaultText;  
[Browsable(true),
    Category("Miscellaneous"),
    DefaultValue(defaultText),
    WebPartStorage(Storage.Personal),
    FriendlyName("Text"),
    Description("Text Property")]
public string Text 
{
    get { return text; }
    set { text = value; } 
}

The first two lines define a default value and a class-wide variable for the custom property value. The last five lines are a very ordinary property definition. The middle six lines, within square brackets, actually define the custom property as it will appear in the Web Part's property pane. Table 19-1 lists and describes all the available properties.

Table 19-1. Custom property attributes

Attribute Purpose
Browsable A value of false stops the custom property from appearing in the Web Part's property sheet The default is true. Setting the WebPartStorage attribute to Storage.None has the same effect.
Category The section title where the custom property will appear on the property sheet. If you leave this attribute empty or set it to Default, Appearance, Layout, or Advanced, the custom property will appear in the Miscellaneous section.
Description The tool tip text that appears if a team member hovers the mouse pointer over the custom property's input control.
DefaultValue The custom property's default value.
FriendlyNameAttribute The caption or title that identifies the custom property. If you leave this empty, the program name for the property will appear.
ReadOnly A value of true makes the custom property read-only in the property sheet. The default is false.
WebPartStorage The view modes for which Windows SharePoint Services will display and save custom property values. The permissible values are:
  • Storage.Shared   Only when configuring the Web Part's shared view.
  • Storage.Personal   When configuring either the shared or personal view.
  • Storage.None   Never.
HtmlDesignerAttribute Associates a property builder (that is, a custom Web page or module) with the property. This overrides the normal input format in Web page designers such as FrontPage.

You can define as many of these custom properties as you need. Windows SharePoint Services takes care of displaying them, and of saving the configured values as part of the Web Part definition for that page (or, in the case of personal views, for that team member). The type of input control depends on the data type of the custom property. For example, a string property will get a text box, and a Boolean property will get a check box.

Of course, it's your responsibility to write code that makes use of the custom property, once received.

If you need the capability of rejecting a custom property, choose one of these approaches:

  • Raise an exception in the property's set method. This approach is simple and normally works as you want in both the SharePoint browser interface and in FrontPage. Instead of closing, the property sheet will display the error message from your exception.

    If, however, your exception occurs when the Web Part's property sheet isn't visible, then the whole page may fail. This can occur, for example, when another control tries to set the property pragmatically.

  • Use a Web Part Tool Part, as the next section describes.

Using Web Part Tool Parts

If the default user interface that Windows SharePoint Services provides for custom properties doesn't meet your needs, Web Part Tool Parts may provide an answer.

Basically, a Web Part Tool Part is a class that displays and processes an HTML user interface for one or more custom properties. To use Web Part Tool Parts, the Web Part class file must override the GetToolParts method with code like this:

public override ToolPart[] GetToolParts() 
{
    ToolPart[] toolparts = new ToolPart[3];
    toolparts[0] = new CustomPropertyToolPart();
    toolparts[1] = new WebPartToolPart();
    toolparts[2] = new WebPartLibrary2.ToolPart1();
    return toolparts; 
}

Notice that this override returns an array of ToolPart objects.

  • The first is a standard CustomPropertyToolPart object, which displays any custom properties just as the previous section described. If you override GetToolParts and omit this entry, no controls for custom properties will appear.
  • The second is a WebPartToolPart object, which displays the standard Appearance, Layouts, and Advanced sections of the Web Part's property pane. If you omit this entry, these sections won't appear.
  • The third (and each subsequent) is a custom class that you develop separately in the same project, and that inherits the Microsoft.SharePoint.WebPartPages.ToolPart class.

Any ToolPart classes you write must override four methods: ApplyChanges, SyncChanges, CancelChanges, and RenderToolPart.

For more information about writing classes that override the ToolPart class, and about using Web Part tool tips in general, see Creating a Web Part with a Custom Tool Part.

Providing a Design Time HTML Provider

If you open a Web Part Page in FrontPage, any custom Web Parts you develop are likely to appear with the following message in place of a WYSIWYG display:

The preview for this Web Part is not available.

This is because FrontPage Design view doesn't actually run any Web Parts it displays: instead, it calls a method called GetDesignTimeHtml and displays the resulting HTML. If your Web Part doesn't override this method, the message shown above appears.

The GetDesignTimeHtml method is part of an interface named IDesignTimeHtmlProvider. Here, then, are the steps necessary for your Web Part to appear graphically in an editor like FrontPage.

  • To signify that your Web Part class supports the IDesignTimeHtmlProvider interface, append a comma and the interface name to the class declaration. For example, change:

    public class SimpleWebPart : 
       Microsoft.SharePoint.WebPartPages.WebPart  
    {}
    

    to:

    public class SimpleWebPart : 
       Microsoft.SharePoint.WebPartPages.WebPart,
       IDesignTimeHtmlProvider 
    {}
    
  • Add a public method such as the following to your class:

    public string GetDesignTimeHtml() 
    {
    return "<p>Any HTML</p>";
    }
    

Of course, the GetDesignTimeHtml method can return any HTML you want. You might arrange, for example, for a common method to format actual data in the RenderWebPart method, and sample data in the GetDesignTimeHtml method.

For more information about using the IDesignTimeHtmlProvider interface, see "Implement the IDesignTimeHtmlProvider Interface in Your Web Part to Ensure Correct Rendering in FrontPage" in Best Practices for Developing Web Parts for SharePoint Products and Technologies.

Assigning a Strong Name

Strong naming is a technique whereby Visual Studio uses a private key to digitally sign any assemblies (for example, any DLLs) it creates. It also stamps those assemblies with a public key that can validate the signature. This guards against any unauthorized versions of a program (such as a Web Part). If the given public key fails to validate the digital signature, or if the assembly contains an unexpected public key, Windows SharePoint Services will refuse to run the module. Instead, you get a message like the following:

A Web Part or Web Form Control on this Web Part Page cannot be displayed or imported because it is not registered on this site as safe.

As you'll learn in the next section, there are two ways of deploying Web Parts: one that requires a strong name and one that recommends one. Here is the procedure for giving a Web Part assembly a strong name:

  1. Identify the folder that contains your Visual Studio Web Part project. The following is a typical path, where *<user>*is your windows logon ID and <project> is the name of your Visual Studio project.

    C:\Documents and Settings\<user>\My Documents\Visual Studio 
    Projects\<project>
    
  2. On the machine running Visual Studio, open a command prompt.

  3. Change to the directory containing the sn.exe file. This is usually one of the following:

    C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin\
    C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin\
    
  4. Create a key pair file by running the following command:

    sn.exe –k "<path>\<project>.snk"
    

    where <path> is the path to your Visual Studio project (from step 1) and <project> is the name of your Visual Studio project.

  5. Open your Visual Studio project, and then choose Add Existing Item from the File menu.

  6. When the Add Existing Item dialog box appears, find and select the file you created in step 4, and then click Open.

  7. In Video Studio, open the AssemblyInfo.cs file for your project.

  8. Scroll to the bottom of the file, and change the line

    [assembly: AssemblyKeyFile("")]
    

    to:

    [assembly: AssemblyKeyFile("..\\..\\<project>.snk")]
    

    where <project> is the name of your Visual Studio project.

    As usual in C literals, a single backslash is an escape character. For example, \n means new line, not a backslash followed by an n. To get a backslash in the literal's value, you have to code two backslashes.

    The path ..\..\ is necessary because the strong name key file resides two directory levels closer to the root than the DLL file Visual Studio creates when it builds your project.

  9. Scroll about halfway up the AssemblyInfo.cs file and look for a line like:

    [assembly: AssemblyVersion("1.0.0.0")]
    

    If this line contains any asterisks, replace them with digits. This will avoid creating a new version number every time you compile the Web Part.

  10. Choose Rebuild Solution from the Build menu. This (and every subsequent build) will create a strongly named assembly.

Tip   Whenever the name, version number, or digital signature of a Web Part changes, you have to reinstall the Web Part on each SharePoint server that uses it, and reconfigure each Web Part page that uses it. as a result, most programmers avoid changing these properties.

Deploying Custom Web Parts

To deploy or upgrade a Web Part, you must first compile it in Visual Studio. Then, you must copy the resulting assembly (that is, the resulting .dll file) into one of two locations:

  • The SharePoint server's Global Assembly Cache (GAC)   This makes the Web Part available to all virtual servers on the same computer, with maximum privileges. However, the assembly must have a strong name. (You must have compiled it with a key pair file.)

    To install a Web Part this way, drag its .dll file into the C:\Windows\Assembly folder, where C:\Windows is the server's system folder.

  • The bin folder of one or more virtual servers   This makes the Web Part available only on those virtual servers where you install it. Assemblies you install this way don't need strong names, but strongly naming your assemblies is always a good idea.

    Unfortunately, at least through windows SharePoint Services Service Pack 1, this method doesn't work properly on computers running more than one SharePoint content server.

There are three ways to install Web Parts into the bin folder of a virtual server.

  • Install the Web Part manually.   To do this:

    1. Create your own .dwp file.
    2. Copy this .dwp file into the wpcatalog folder at the virtual server's physical root.
    3. Copy the Web Part's .dll into the bin folder at the virtual server's physical root.
    4. Update the <SafeControls> section of the virtual server's web.config file.
  • Create and install a Web Part Package.   To take this approach, create a Windows CAB file (with a .wpp file name extension) that contains:

    • A mainfest.xml file describing each file you need to install.
    • Each file you need to install.
  • Then, run the following command to install the package:

    stsadm.exe –o addwppack –filename <filename> –globalinstall -force
    

    where <filename> is the name of the .cab file.

  • Use the InstallAssemblies tool.   This tool examines your .dll file, creates the required .dwp file and Web Part Package, and then runs stsadm.exe –o addwppack, all from a graphical interface. In almost every case, this is the easiest, most accurate, and overall best approach.

To install the InstallAssemblies tool, copy the \utils\Web Part Toolkit\ folder on the companion CD to a C:\Program Files\Web Part Toolkit\ folder on your SharePoint server. Then, to run the tool, launch C:\Program Files\Web Part Toolkit\InstallAssemblies\InstallAssemblies.exe.

After you install a Web Part to either the global assembly cache or a virtual server's bin folder, you can usually install new versions simply by dragging the .dll file into the same folder as its predecessor. However, this won't work if you've changed the file's name, version number, or strong key signature.

Unless you manually installed a .dwp file in the virtual server's wpcatalog folder, New Web Parts don't appear automatically in the Web Part gallery of any site collection. To make them appear, a site collection administrator will need to add them.

For instructions on adding a Web Part to a Web Part gallery, refer to "Managing the Web Part Gallery" in Chapter 17.

If you added your Web Part to the bin folder of one or more virtual servers, and running it produces a security failure, you may need to locate the following tag in the server's web.config file:

<trust level="WSS_Minimal" originUrl="" />

and change WSS_Minimal to WSS_Medium or Full. Keep in mind, however, that this grants increased privileges to all Web Parts run from the virtual server's bin folder.

To configure a trust level that grants privileges to a specific assembly, see "To Give Access To An Assembly" in Microsoft Windows SharePoint Services and Code Access Security.

After you install or update a Web Part assembly or a .dwp file, and after you modify the config.sys file, the change may not take effect until after you stop and restart the Internet Information Services (IIS) server. To do this, open a command prompt on the server and run the iisreset command.

For more information on deploying Web Parts, see Packaging and Deploying Web Parts for Microsoft Windows SharePoint Services.

For additional guidance in creating Web Parts, try browsing these resources:

In Summary

This chapter explained the basics of how Web Parts work, and what tools you need to create Web Parts of your own. It then explained the basic programming techniques you need to successfully create and deploy custom Web Parts.

The next chapter will provide step-by-step instructions for creating some simple but practical custom Web Parts.