Best Practices for Developing Web Parts for SharePoint Products and Technologies

 

Susan Harney
Microsoft Corporation

June 2004

Applies to:
    Microsoft Windows SharePoint Services
    Microsoft Office SharePoint Portal Server 2003

Summary:   Using the programming model behind Windows SharePoint Services, you can create your own Web Parts that provide new functionality to enhance your Web Part Pages. Learn best practices to improve performance and usability of Web Parts, and ways to create Web Parts that integrate well with other components of a Web Part Page. (15 printed pages)

Contents

Introduction
Handle All Exceptions to Prevent Web Part Page Failures
Check Permissions Before Rendering Your Web Part and Customize the User Interface Accordingly
Validate Properties Whenever You Attempt to Save Changes to the Database
Specify Custom Error Messages When Appropriate
Validate All User Input
Register the Client-side Script Shared by Multiple Web Parts to Improve Performance
Specify Whether Web Part Properties Can be Exported
Implement the IDesignTimeHtmlProvider Interface in Your Web Part to Ensure Correct Rendering in FrontPage
Make Properties User-Friendly in the Tool Pane
HTMLEncode All User Input Rendered to the Client
Check Web Part Zone Properties Whenever You Attempt to Save Changes to Your Web Part
Use Simple Types for Custom Properties You Define
Make Properties Independent of Each Other if They both Appear in the Tool Pane
Make Web Parts Easily Searchable in the Galleries
Provide a Preview of Your Web Part for the Web Part Gallery
Techniques to Improve Web Part Performance
Localize Your Custom Property's FriendlyName, Title, and Description Attributes
Conclusion

Introduction

This article offers guidelines that are recommended best practices for Web Part developers. You can use them to improve the performance and usability of the Web Parts you design, and to assist you to create Web Parts that integrate well with other components of a Web Part Page.

Note   These guidelines are common to all Web Parts. They are not designed to test Web Part-specific functionality.

Handle All Exceptions to Prevent Web Part Page Failures

Your Web Part should handle all exceptions rather than risk the possibility of causing the Web Part Page to stop responding.

You can help make this possible by placing the sections of code that might throw exceptions in a try block and placing code to handle these exceptions in a catch block. Following is an example.

private void SetSaveProperties()
{
   if (this.Permission !=    
      Microsoft.SharePoint.WebPartPages.Permissions.None)
   {
      try
      {
         SaveProperties = true;
      }

      Catch (Exception ex)
      {
      // Setting SaveProperties can throw many exceptions. 
      // Two examples are:
      // 1) SecurityException if the user doesn't have the "ObjectModel"
      //    SharePointPermission or the "UnsafeSaveOnGet"
      //    SharePointPermission
      // 2) WebPartPageUserException if the user doesn't have sufficient
      //    rights to save properties (for example, the user is a Reader)
         errorText = ex.Message;
      }
   }
}

For more information, see Using the Try/Catch Block to Handle Exceptions in the .NET Framework Developer's Guide in the MSDN Library.

Check Permissions Before Rendering Your Web Part and Customize the User Interface Accordingly

Because Web Parts are managed by the user at run time, you should render your Web Part with a user interface that is appropriate for each user's permissions. To do this, always check the Permissions property before rendering the Web Part—if the value is None, you should suppress the portions of your Web Part user interface that require certain permissions. For example, if a Web Part displays a Save button, you can disable or hide it if the user does not have permissions to save changes.

If a user is unable to use your Web Part as you designed it, several things could be happening:

  • The user is a Reader.
  • The Web Part is not in a Web Part zone. Although your Web Part may be designed to be dynamic, if a user adds it to a blank page in Microsoft Office FrontPage 2003, for example, it becomes a static Web Part. Static Web Parts cannot save changes in either shared or personal view.
  • The user is anonymous.

For more information, see the Permissions property in the Microsoft SharePoint Products and Technologies 2003 Software Development Kit (SDK).

Validate Properties Whenever You Attempt to Save Changes to the Database

You can edit property values in a number of places outside of your Web Part's UI, for example:

  • In the Web Part description (.dwp) file.
  • In the tool pane.
  • In an HTML editor compatible with Windows SharePoint Services, such as FrontPage 2003
  • Using the Web Part Pages Services Component (WPSC) to set properties from the client browser.

Because of the variability of places in which you can edit property values, whenever you attempt to save changes to the database you should not make assumptions about the state of your properties. For example, you cannot assume that properties are unchanged because you suppressed them in the UI, or that properties are valid because you validated them when they were entered in the user interface.

To make sure that you account for all the different places that properties can be set, we recommend that you place your validation code in the property's Set accessor method.

Specify Custom Error Messages When Appropriate

By default, when an exception occurs, the Web Part infrastructure redirects the user to an error page and renders a generic error message. To specify your own error message to the end user, use the WebPartPageUserException class, as shown in the following example.

If (ex is WebPartPageUserException)
{
   errorText = ex.Message
{

For more information, see WebPartPageUserException class in the Microsoft SharePoint Products and Technologies 2003 SDK.

Validate All User Input

Like any Web control or application, you should thoroughly validate all user input before performing operations with that input. This validation can help to protect against not only accidental misuse, but also deliberate attacks such as SQL injection, cross-site scripting, buffer overflow, and so on.

For more information about creating secure Web Parts, see the Microsoft Security Developer Center.

Register the Client-side Script Shared by Multiple Web Parts to Improve Performance

There are two ways to render client-side script for a Web Part page.

  • Place the script in an external file and register the script for the page.
  • Send code to the client for each request.

If you have multiple Web Parts that share client-side script, you can improve performance and simplify maintenance by placing the script in an external file and registering the script for the page. In this way, the code is cached on the client computer on first use and does not need to be resent to the client for each request.

To register client-side script shared by multiple Web Parts

  1. Place the script in a separate file.
  2. Create the appropriate folder on the server to save the file.If the assembly is deployed in the global assembly cache, save the script file in the _wpresources virtual directory If the assembly is located in the bin, save the script file in the wpresources virtual directory
  3. In your Web Part code, register the script using the page's RegisterClientScriptBlock method.

For detailed instructions, see Creating a Web Part with Client-side Script in the Microsoft SharePoint Products and Technology 2003 SDK.

Specify Whether Web Part Properties Can be Exported

When you export a Web Part, you create a Web Part description (.dwp) file automatically. The .dwp file is an XML document that represents the Web Part and its property values. Users can import this file to add the Web Part with all the properties set.

By default, each property is included in the .dwp file whenever you export a Web Part. However, because you may have properties that contain sensitive information, for example, a date of birth, the Web Part infrastructure enables you to identify a property as controlled, allowing you or the user to have the choice to exclude the value if the Web Part is exported. Only properties that are exported when the user is in personal view can be controlled; in shared view, all property values are exported because it is not likely that sensitive information would be included on a shared page.

There are two properties that work together to provide this functionality: the ControlledExport property of the WebPartStorageAttribute class, and the ExportControlledProperties property of the WebPart class.

ControlledExport

The ControlledExport property of the WebPartStorageAttribute class, if set to true, specifies the property as a controlled property. This property is defined along with other property attributes as follows:

[WebPartStorage (Storage.Personal, ControlledExport=true)]

Note   If no WebPartStorage attribute is defined, or if the ControlledExport property is not explicitly included, this value is false.

ExportControlledProperties

The ExportControlledProperties property of the WebPart class is used at run time to determine whether controlled properties are exported when the user is in personal view. The default value is false, which prevents properties from being exported while in personal view.

This property maps directly to the Allow Export Sensitive Properties check box in the Advanced category of the tool pane, enabling the user to set this value at run time. By default, this check box is not selected, which prevents controlled properties from being exported. The user has to explicitly select this check box to allow different behavior. (This option applies only to controlled properties.)

Figure 1. Advanced category as viewed in the tool pane

Note   The Advanced category in the tool pane appears only in the view in which the Web Part was added. For example, if the Web Part is added in shared view, the Advanced section appears in the tool pane only when you are modifying properties in the Shared Page; if it is added in personal view, the Advanced section of the tool pane appears only when you are modifying properties in My Page. In either case, the setting determines how properties are exported only when the user is exporting in personal view.

Implement the IDesignTimeHtmlProvider Interface in Your Web Part to Ensure Correct Rendering in FrontPage

Because Microsoft Office FrontPage is the environment where many end users edit Web Part Pages, you should make sure your Web Parts render correctly there. You can specify how you want your Web Part to render in the FrontPage Design view by implementing the IDesignTimeHtmlProvider interface.

If you do not implement this interface, and a user opens a Web Part Page in the FrontPage Design view, your part appears only as the message, "There is no preview available for this part."

Following is an example of a simple IDesignTimeHtmlProvider implementation.

namespace MyWebParts
{
   [XmlRoot(Namespace = "MyNamespace")]
   public class DesignTimeHTMLSample :  
      Microsoft.SharePoint.WebPartPages.WebPart, IDesignTimeHtmlProvider 
   {
      private string designTimeHtml = "This is the design-time HTML.";
      private string runTimeHtml = "This is the run-time HTML.";

      public string GetDesignTimeHtml()
      {
         return SPEncode.HtmlEncode(designTimeHtml);
      }
      protected override void RenderWebPart(HtmlTextWriter output)
      { 
         output.Write(this.ReplaceTokens(runTimeHtml));
      }
   }
}

For more information, see the IDesignTimeHtmlProvider interface in the Microsoft SharePoint Products and Technologies 2003 SDK.

Make Properties User-Friendly in the Tool Pane

Because the tool pane is where users modify Web Part properties, you should be aware of how your properties appear in it. Following are some attributes you should use to ensure that your users can work with your Web Part properties easily in the tool pane.

  • FriendlyNameAttribute.   Controls how the property name is displayed.

    This name should be user friendly, for example, a property named MyText should be "My Text" (notice the space between the two words).

  • Description.   Specifies the tool tip shown when the user pauses the mouse pointer over the property.

    Try to write the property description so that a user can figure out how and why they should set the property. Try to minimize users having to navigate away from your UI and seek help in the documentation to set a property.

  • Category.   Describes the general section the property belongs to, for example, Advanced, Appearance, Layout, or Miscellaneous.

    If possible, avoid the Miscellaneous category, which is used if no category is specified for a property. Because this category title is not descriptive, your user has no indication of what is included in Miscellaneous without expanding it.

    A custom property is also placed in the Miscellaneous category if you attempt to include it in the Appearance, Layout, or Advanced categories. These categories are reserved for base class properties only.

For example, the following attribute statements demonstrate the attributes for a custom property that is a string displayed as a text box in the tool pane.

// Create a custom category in the tool pane.
[Category("Custom Properties")]
// Assign the default value.
[DefaultValue(c_MyStringDefault)]
// Make property available in both Personalization
// and Customization mode.
[WebPartStorage(Storage.Personal)]
// The caption that appears in the tool pane.
[FriendlyNameAttribute("My Custom String")]
// The tool tip that appears when pausing the mouse pointer over
// the friendly name in the tool pane.
[Description("Type a string value.")]
// Display the property in the tool pane.
[Browsable(true)]
[XmlElement(ElementName="MyString")]

Additional Customization Tips for Properties in the Tool Pane

You can customize the appearance of your properties in the tool pane by doing the following:

  • Expanding and collapsing specific categories when the pane opens.

    Use the Expand method of either the WebPartToolPart or CustomPropertyToolpart class to expand selected categories.

  • Hiding base class properties.

    Use the Hide method of the WebPartToolPart class to hide selected properties.

  • Controlling the order of tool parts within a tool pane.

    Order the tool parts as you want them to appear in the tool pane in the array passed to the GetToolParts method of the WebPart class.

For more information, see Creating a Web Part with Custom Properties in the Microsoft SharePoint Products and Technologies 2003 SDK.

HTMLEncode All User Input Rendered to the Client

Use the HTMLEncode method of the SPEncode class as a security precaution to help prevent malicious script blocks from being able to execute in applications that execute across sites. You should use HTMLEncode for all input that is rendered to the client; this can reduce dangerous HTML tags to more secure escape characters.

Following is an example of using the HTMLEncode method to render HTML to a client computer.

protected override void RenderWebPart(HtmlTextWriter output)
{
   output.Write("<font color='" + SPEncode.HTMLEncode(this.Color) + "'>"
      + "Your custom text is: <b>" + SPEncode.HTMLEncode(this.Text) 
      + "</b></font><hr>");
}

For more information, see the SPEncode class in the Microsoft SharePoint Products and Technologies 2003 SDK.

Check Web Part Zone Properties Whenever You Attempt to Save Changes to Your Web Part

Web Part zones have properties that control whether a user can persist changes. If you attempt to save changes to a Web Part without the correct permissions, it could result in a broken page. For this reason, you should account for any combination of permissions for your Web Part.

Following are the list of properties in the WebPartZone class that determine whether a Web Part can persist properties:

  • AllowCustomization property. If false, and the user is viewing the page in shared view, the Web Part cannot persist any changes to the database.
  • AllowPersonalization property. If false, and the user is viewing the page in personal view, the Web Part cannot persist any changes to the database.
  • LockLayout property. If true, changes to the AllowRemove, AllowZoneChange, Height, IsIncluded, IsVisible, PartOrder, Width, and ZoneID properties are not persisted to the database regardless of view.

Fortunately, the Web Part infrastructure does a lot of the work. You can check the Permissions property, which takes into account the values of the zone's AllowCustomization and AllowPersonalization properties. If, however, your user interface permits changes to the properties controlled by the LockLayout property, you must explicitly check this value, typically in your property's Set accessor method.

The following code illustrates how you can get a reference to a Web Part's containing zone to check the LockLayout property.

WebPartZone myParent = (this.Page.FindControl(this.ZoneID));

Use Simple Types for Custom Properties You Define

Web Part property values can be specified in one of two ways:

  • As XML elements contained in the Web Part.

    For example,

    <WebPartPage:ContentEditorWebPart runat=server>
    <WebPart>
       <title>My content Web Part</title>
       <description>This is cool</description>
    </WebPart>
    </WebPartPages:ContentEditorWebPart>
    
  • As attributes of the Web Part

    For example,

    <WebPartPage:ContentEditorWebPart runat=server title="My content Web Part" description="this is cool" />
    

Because of how the Web Part infrastructure handles property values, we recommend that you define your properties as simple so they work properly if specified as attributes of the Web Part.

If your code requires a value to be a complex type, you can convert the value to a complex type as required by your program.

For a list of simple types, see C# Simple Types, or Visual Basic .NET Primitive Types.

Make Properties Independent of Each Other if They both Appear in the Tool Pane

There is no guarantee of the order that properties are set in the tool pane. For this reason, Web Part developers should avoid writing Web Part properties that are dependent on each other and that both appear in the tool pane.

For example, if logic in property A's set function sets B=2 if A=1, and if the end user inputs A=1 and B=4 in the tool pane and clicks Apply, then property A might get set first, setting B to the value of 2. However, then B is set again to 4 based on the user input, resulting in values of A=1 and B=4.

Make Web Parts Easily Searchable in the Galleries

Web Part galleries can contain numerous custom Web Parts, so the Web Part infrastructure provides Search capability to help users quickly find the Web Parts they want.

Figure 2. The search box for Web Parts

Search uses the Title and Description properties of your Web Part to build the result set, so you should provide comprehensive information in these fields to increase the chance of your Web Part being returned from Search.

In addition, each Web Part in the Web Part List has an icon that appears on the left.

Figure 3. A Web Part icon

By default, the Web Part infrastructure uses generic icons for each Web Part; however, you can customize this icon using the PartImageLarge property.

Be sure to create previews for your Web Parts so that administrators are able to review the parts included in the Web Part gallery.

In your RenderWebPart method, you can determine whether you are in preview mode using the following code.

if (this.Parent.GetType().Fullname = "Microsoft.SharePoint.WebPartPages.WebPartPreview") 

If you are in preview mode, you should render the HTML for the content you want to appear in the preview—typically an image. The chrome and title bar are provided by the infrastructure, with the Web Part title appearing in the title bar.

To view a Web Part preview, follow these steps.

  1. On the top-level site, select Site Settings, then Go to Site Administration.
  2. Select Manage Web Part Gallery to see the list of available Web Parts.
  3. Click on the Web Part name and the preview is displayed if one is available.

Techniques to Improve Web Part Performance

If your Web Part is working with large amounts of data, you can significantly improve its performance by using the following techniques in your code.

Asynchronous Data Fetching

Use an asynchronous thread for any operation that could take a significant amount of time. In particular, if a database or HTTP request is made, an asynchronous fetch allows other parts to continue processing without being blocked.

To register asynchronous operations, call the RegisterWorkItemCallback method of the WebPart class before calling the RenderWebPart method. At the beginning of the render cycle, the base class waits for any pending work items.

Note   The RegisterWorkItemCallback method operates in a manner similar to System.Threading.ThreadPool.QueueUserWorkItem, but is implemented to work with the event model within a Web Part Page.

For more information, including details particular to connectable Web Parts, see Asynchronous Data Fetching in the Microsoft SharePoint Products and Technologies 2003 SDK.

Caching

Use a Web Part cache to store property values and to expedite data retrieval. Values are stored in the Web Part cache on a per-part or per-user basis by specifying the storage type in the call to the PartCacheRead and PartCacheWrite methods.

You can also determine the type of cache to use—either the content database (objects must be serializable) or the ASP.NET Cache object—by setting the value of the WebPartCache element in the web.config file.

Note   By default, exceptions related to caching are not propagated to the surface by the Web Part infrastructure. For debugging purposes, you can make the following changes to your web.config file.

  • In the <SharePoint> tag, locate the <SafeMode MaxControls="50" CallStack="false"/> tag and change it to <SafeMode MaxControls="50" CallStack="true"/>, causing the ASP .NET error message to display with stack trace information.
  • In the <system.web> tag, locate the <customErrors mode="On"> tag and change it to <customErrors mode="Off" /> to see the ASP .NET exception when an error occurs instead of being redirected to the error page. 

**Note   **For security reasons, these changes are recommended for a development environment only; this information is not suitable for a production environment as it can contain sensitive data.

For more information about caching, see Web Parts and Caching in the Microsoft SharePoint Products and Technologies 2003 SDK.

Localize Your Custom Property's FriendlyName, Title, and Description Attributes

By planning for localization at the development phase, you can provide a more usable user interface and save the costs associated with localizing your Web Part post-development. The Web Part infrastructure provides a simple way to localize certain attributes (FriendlyName, Category, and Description) of your custom properties, making it easier for users to work with them in the tool pane.

To localize the FriendlyName, Title, and Description property attributes as they appear in the tool pane

  1. Add an assembly resource file to your project.

    With your project open in Microsoft Visual Studio .NET, click Add New Item, and then select Assembly Resource File. (This adds Resource1.resx file to your project.)

  2. Enter your localized strings to the .resx file.

    Select the Resource1.resx file and enter a localized string for FriendlyName, Category, and Description.

    Figure 4. Assembly Resource File data as viewed in Visual Studio .NET 2003

  3. Add the ResourceAttribute attribute to each property you localize.

    The ResourceAttribute attribute takes three string parameters, which map to the name values you entered in the .resx file, in this case PropertyNameID = 1, CategoryID=2, and DescriptionID = 3.

    [ResourceAttribute ("1", "2", "3")]

  4. Override the LoadResource method of the WebPart class.

    This method takes one string called id, which is the string passed to ResourceAttribute. The Web Part infrastructure passes this string to the LoadResource method.

    Following is an example of the LoadResource function.

    public override string LoadResource (string id)
    {
       ResourceManager rm = new
          ResourceManager("MyNameSpace.Resource1",
          Assembly.GetExecutingAssembly());
       return rm.GetString(id);
    }
    
  5. Create a .resource file by using the ResGen tool provided by .NET Framework tools.

    In a command prompt window enter:

    cd c:\Program Files\<Your Visual Studio .Net folder>\<SDK>\Bin

    Then type the following:

    ResGen <path of your Resource1.resx file>

For more information, including a code sample, see the ResourcesAttribute class in the Microsoft SharePoint Products and Technologies 2003 SDK.

Ensure that When Anonymous Access is On, the User Can View the Web Part Page without Logging In

You do not want to prompt users for a login if the site has anonymous access enabled. You can determine whether anonymous access is enabled by querying the AllowAnonymousAccess property of the SPWeb class. If this value is true, anonymous access is enabled and you should not perform any action that requires credentials.

Conclusion

This article presents best practices that can assist you when developing Web Parts. By using some of these techniques, you can reduce the chance for errors and improve the performance and usability of your Web Parts.