Monday, December 1, 2008

Adding validation to a custom list control in Sharepoint

Introduction

Recently one of the requirements was to put validation to a custom list controls such as Email field validation.
This validation can be achieved from inside the sharepoint designer.
Following is a step by step walk through to validate a list field

Background

You should know how to create a Sharepoint list and how to open the site in Sharepoint designer.


  1. Following is a list with Email fields. Let's say we have to validate so that only a valid email can be entered.
    If not valid then the Error Message appears next to the field
    072908_0945_Addingvalid1.png



  2. Now open the site in the sharepoint designer and then expand the list and open the Newform.aspx of the list to be validated

    072908_0945_Addingvalid2.png

  3. As you can see in the image above the Newform.aspx of Validation list is being opened in the sharepoint Designer.

  4. Now right click on this Validation list web part in sharepoint Designer and choose Web Part properties
    072908_0945_Addingvalid3.png



  5. The properties dialog box will open for the Validation list here. Choose Hidden under layout and say ok.
    (This web part can be deleted as well, but due to some Known problems because of deletion it is best to hide this).
    072908_0945_Addingvalid4.png



  6. Now click exactly underneath the hidden list web part and go to Insert->Sharepoint Controls-> Custom List Form… and Wizard will ask to choose a List or Document Library form on based
    Of existing list. Choose your Validation list and select New item form under type of from to create option and hit Ok.
    072908_0945_Addingvalid5.png



  7. You will get the Validation List underneath the hidden list as shown as selected image below.
    072908_0945_Addingvalid6.png



  8. Now from here we can customize all the controls based on requirement. As we are customizing the E-Mail
    Field, right click on the email field box and choose Show common control tasks from the context menu.
    072908_0945_Addingvalid7.png



  9. This will give you Common Formfield tasks option as shown below next to Email field. Here we can change
    The format of the data field selected (default is List form field). As we need Email field to be textbox where validation can be applied
    Choose Textbox from Format as dropdown instead of List form field.
    072908_0945_Addingvalid8.png



  10. After the above step, List will look like this (custom formatted)
    072908_0945_Addingvalid9.png



  11. Now drop a RegularExpressionValidator control from the Validation option under ASP.Net controls from the toolbar
    As shown below
    072908_0945_Addingvalid10.png




  12. Now specify the required properties (such as ControlToValidate, ErrorMessage, SetFocusOnError to true, Validate Expression) of the
    RegularExpressionValidator from the Tag Properties toolbar. For ControlToValidate choose the ID of the Email field
    After selecting it and getting the ID from the Tag Properties toolbar as you do in Visual Studio. See below the set attributes in blue
    For the Email Field
    072908_0945_Addingvalid11.png



  13. Now Save the changes and go back to the list in IE and try to type in invalid email id and you will get following
    072908_0945_Addingvalid12.png




Extending SharePoint Server 2007 by using Features

Introduction

The Feature Framework has been extended to allow developers to create custom Features. Features can be deployed by using SharePoint Portal Server 2007 new form of deployment, namely Solution Deployment. Solutions are custom packages (e.g. WSP file) or redistributable CAB files, created by developers and deployed by SharePoint Administrators. Administrator can deploy Features to the individual site or to all Web front End Servers.
In this article, I will walk-through Creating and deploying an Event Handler Feature, which can be activated on the Web or Site, Site Collection, Web Application or Farm Level.

Components of Feature

A Feature can include any number of files, but it must include a Feature.xml file. The Feature.xml file, or Feature manifest, is the driver of the Feature, and this is the first file SharePoint looks at when invoking a Feature.
Features are organized in folders under the Features directory located under 12 hives; Where SharePoint Server 2007 puts all of its system files, at the following path: %SystemDrive%\Program Files\Common Files\Microsoft Shared\web server extensions\12.
In addition to the Feature.xml file, Features can include sub-folders and supporting files, such as element files that include for example, event handler references, ASPX pages deployed as part of the Feature, ASCX files, and DLL and RESX files.

Event Handler Feature

SharePoint Event Handler is a program that enhances and adds functionality throughout SharePoint List, List Items or Sites. Event Feature can be deployed to new or existing sites by using Features. SharePoint Object Model provides several event classes that can target event handlers to List, List Item or Sites.

Synchronous and Asynchronous Events

In addition to asynchronous events, SharePoint Server 2007 introduces synchronous events i.e. events that activate before the action occurs. Synchronous events can trap an item, document library or site before it is deleted. Synchronous events removed the ability for users to delete an item from the document library or event restricts users to delete columns from the document library.
SharePoint Object Model exposes several event classes inherited from Microsoft.SharePoint assembly. There are three main event classes:
  • SPItemEventReceiver
  • SPListEventReceiver
  • SPWebEventReceiver
Each class includes both synchronous and asynchronous methods to work with Item, List or Web Level. In this article, I will demonstrate how to hook an ItemDeleting, FieldDeleting or SiteDeleting Event to restrict users from deleting an item from the document library or from deleting a column from the document library.

SPItemEventReceiver

By overriding a member of the SPItemEventReceiver class, developers can restrict users from deleting, updating an Item in a List. Some of the important SPItemEventReceiver class members are described below:
Event Event Type Description
ItemAdded Asynchronous After an Item added in a list
ItemAdding Synchronous Before an Item added in a list
ItemAttachmentAdded Asynchronous After an attachment added from a list item
ItemAttachmentAdding Synchronous Before an attachment added from a list item
ItemAttachmentDeleted Asynchronous After attachment deleted from a list item
ItemAttachmentDeleting Synchronous Before attachment deleted from a list item
ItemCheckedOut Asynchronous After an item checked-In in a list
ItemCheckingOut Synchronous Before an item is checked out in a list
ItemCheckedIn Asynchronous After an item is checked-In in a list
ItemCheckingIn Synchronous Before an item is checked-In in a list
ItemDeleted Asynchronous After an item is deleted from a list
ItemDeleting Synchronous Before an item is deleted from a list
ItemUpdated Asynchronous After an item is updated in a list
ItemUpdating Synchronous Before an item is updated in a list
For the demonstration, I am using a synchronous event i.e. ItemDeleting, which restricts users from deleting an item in a list (document library). You can invoke this event with any type of list of document library by specifying the ListTemplateId attribute in a Feature Schema file e.g. ItemEventReceiver.xml.
See the screenshot below of ItemEventReceiver.cs and ItemEventReceiver.xml for defining the ListTemplateId and Assembly.
ItemDeletingEvent.JPG
ItemEventReceiver.cs class

ItemDeletingEvent.JPG
ItemEventReceiver.xml file
The following table shows the default list template integer IDs that you can use in defining the template ID for event handlers.
List Template Id List Template
100 Generic list
101 Document library
102 Survey
103 Links list
104 Announcements list
105 Contacts list
106 Events list
107 Tasks list
108 Discussion board
109 Picture library
110 Data sources
111 Site template gallery
113 Web Part gallery
114 List template gallery
115 XML Form library
120 Custom grid for a list
200 Meeting Series list
201 Meeting Agenda list
202 Meeting Attendees list
204 Meeting Decisions list
207 Meeting Objectives list
210 Meeting text box
211 Meeting Things To Bring list
212 Meeting Workspace Pages list
300 Portal Sites list
1100 Issue tracking
2002 Personal document library
2003 Private document library

SPListEventReceiver

By overriding a member of the SPListEventReceiver class, developers can restrict users from deleting, updating a list from a Site. Some of the important SPListEventReceiver class members are described below.
Event Event Type Description
FieldAdded Asynchronous After a document is added in a List
(Document Library)
FieldAdding Synchronous Before a document is added in a List
(Document Library)
FieldDeleted Asynchronous After a document is deleted from a list
(Document Library)
FieldDeleting Synchronous Before a document is deleted from a list
(Document Library)
FieldUpdated Asynchronous After a document is updated in a list
(Document Library)
FieldUpdating Synchronous Before a document is updated in a list
(Document Library)
For the demonstration, I am using a synchronous event i.e. FieldDeleting, which restricts users from deleting a document from a list (Document Library). In this case, I am again specifying ListTemplateId = 101 for Document Library in a ListEventReceiver.xml file.

SPWebEventReceiver

By overriding a member of the SPWebEventReceiver class, developers can restrict users from deleting a site from a site collection or even completely delete a site collection. Some of the important SPWebEventReceiver class members are described below:
Event Event Type Description
SiteDeleted Asynchronous After a site collection has been deleted
SiteDeleting Synchronous Before a site collection is being deleted
WebDeleted Asynchronous After a web site has been deleted
WebDeleting Synchronous Before a web site is being deleted
For the demonstration, I am using a synchronous event i.e. WebDeleting, which restricts users from deleting a web site from a site collection.

Building the Solution

We need Visual Studio 2005 to create a solution for providing the required functionality.
The steps required to create an event handler for SharePoint Sever application are described below:
  • Create a C#.NET Class Library Solution in Visual Studio .NET 2005 and give a name, such as EventHand<code>lerFeature
  • On the Project Menu, choose Add Reference to Open Reference dialog box
  • Scroll down to Windows SharePoint Services and click the references the Microsoft.SharePoint.dll
  • Create a new folder inside Project Solution and give a name such as Features
  • Create three folders inside Features folder and give names such as ItemEventReceiver, ListEventReceiver and WebEventReceiver folders.
  • Create Feature.XML and feature schema file for ItemEventReceiver folder.

Attributes of Feature.XML File

Some of the attributes of Feature Tag are described below:
Attribute Value Description
ID GUID Contains the globally unique identifier (GUID) for the Feature.
Title Text Returns the title of the Feature. Limited to 255 characters.
Scope Farm/WebApplication/Site/Web Can contain one of the following values: Farm (farm), WebApplication (Web application), Site (site collection), and Web (Web site).
Hidden True/False This attribute equals FALSE by default.
AlwaysForceInstall True/False Optional Boolean. TRUE if the Feature is installed by force during installation even if the Feature is already installed. For example, if set to TRUE, Feature installation callouts will always fire anytime a user tries to install the Feature (even if it is already installed) by using either the scanforfeatures or installfeature command-line operation. This attribute equals FALSE by default. The AlwaysForceInstall attribute affects Features of all scopes.
See screenshot below of Feature.XML file.
FeatureXML.JPG
  • Repeat the above step from ListEventReceiver and WebEventReceiver folders
  • Create a new C#.NET class and give a name, such as ItemEventReceiver.cs class. Add Microsoft.SharePoint namespace and inherit this class from SPItemEventReceiver class in order to override ItemDeleting member for restricting users from deleting an Item from a list or document library
  • Repeat the above step and create two more classes and give names, such as ListEventReceiver.cs and WebEventReceiver.cs
  • Build the Solution
  • Sign the solution by using SN utility of .NET command prompt or specifying the Sign Assembly name in the solution properties.
Note: Complete source code of solution and package file is attached with this article.

Packaging the Features

In SharePoint Server 2007, Solutions are used to package and deploy Features, Site Definitions, Web Parts, Template Files, Assemblies and Code Access Security (CAS) policies to SharePoint front-end servers.
Steps for creating a Solution Package are described below:
  • Create Manifest.XML file as part of the same project, which contains information Solution and path of feature files as part of the overall solution.
  • Create the Diamond Discovery File i.e. DDF file, which contains information to compress files into a CAB file.
  • In the windows command prompt, run MakeCab.Exe on the DDF file to generate the WSP file. Note: MakeCab.Exe file can be downloaded from the Microsoft Site and should be copied into the same directory containing the Visual Studio Project Files.
  • See screenshot below to make WSP file by using MakeCab.EXE command line utility.
Make WSP Cabinet File.JPG

Deploying the Features

Steps for deploying a Solution Package are described below:
  • Use the STSADM.EXE command line tool to add WSP file into the SharePoint Solution Store.
add solution.JPG
  • Navigate to SharePoint Central Administration Page.
  • Click "Operation" Tab and Select "Solution Management" to see the list of solutions deployment in a Farm.
pg1.JPG
See screen below for a list of solutions deployed in a farm.
pg2.JPG
  • Click EventHandlerFeature link to deploy the solution to specified Web Application.
  • Click "Deploy Solution" to deploy the EventHandlerFeature Solution to Web Application. See screenshot below.
pg3.JPG
  • Select "Web Application" and Click "OK" to deploy the solution. See screenshot below for details.
pg3.JPG

Activating the Solution

  • Now navigate Site Settings and Select Site Features of the required web site.
  • Select the desired Site Feature and click "Activate" button to activate the Feature. See screenshot below for details.
pg6.JPG
  • You can use STSADM command line utility to activate a feature on a particular web site by specifying the URL.
Activate.JPG

Testing the Solution

  • ItemEventResource Feature:
Navigate to a Document Library in a Site, Where you have activated ItemEventResource feature.
    • Select a document and click "Delete" to delete the document.
    • SharePoint will generate an error page stating that you cannot delete an item from document library.
    • De-Activate the feature and try to delete the same document from the library. Now, in this instance, you can successfully delete the document.
pg8.JPG
  • ListEventResource Feature:
Navigate to a Document Library in a Site, Where you have activated ListEventResource feature.
    • Select "Settings" and click "Document Library Settings" to navigate the document library settings page.
    • Select any column and delete a column from the Document Library.
    • SharePoint will generate an error page stating that you cannot delete columns from this Document Library.
pg7.JPG
  • WebEventResource Feature:
Navigate to a Site in a Web Application, Where you have activated WebEventResource feature.
    • Click Site Action and Settings.
    • Click "Delete this Site" to delete the site.
    • SharePoint will generate an error page stating that you cannot delete this Site from the Web Application.
      Note: Please first try this solution to a testing environment in order to avoid any catastrophe.

Deactivating and Uninstalling the Solution

You can choose to turn deactivate a particular feature on your site or web application, or you can choose to uninstall a feature, which completely removes the feature from your SharePoint deployment. Features can be deactivated either through the administrative user interface or by using the STSADM.EXE command-line tool.
  • Deactivating the Feature by administrative user interface:
    • Browse the site where you want to deactivate the feature, Click Site Actions, and under Site Administration, click Site Features.
    • On the Site features page, locate the Feature you want to deactivate and click the Deactivate button to deactivate the Feature
deactivate.JPG
  • Deactivating the feature by using the STSADM.EXE command-line utility:
    • Open the Windows command-line tool and type the following command: STSADM.EXE –o deactivatefeature –name ItemEventReceiver –url http://mtech.litwareinc.com/
  • Uninstalling the Feature by using the STSADM.EXE command-line utility
    • Open the Windows command-line tool and type the following command: STSADM.EXE –o uninstallfeature –name ItemEventReceiver –force
Note: Files deployed as part of the Feature, such as ASPX, ASCX files are not removed when a Feature is uninstalled.

Use SharePoint User or Group Picker in your WebParts/user controls

Introduction

SharePoint has a user and group picker which allow browsing SharePoint users and groups. Sometimes, we need to use the user group browsing facility in our custom WebPart or user controls. I have used Firefox Firebug to inspect the way the user group picker works. And, I have got the way it works! I think I need to share this with everyone.

Basics

The SharePoint provided user/group picker contains four controls as shown in figure 1 and described below:
  1. A textbox to enter user/group name.
  2. A check-name icon to check if the user/group name is valid.
  3. A browse icon to allow user/group to be searched.
  4. A hidden control which shows messages when user/group name not found.
  5. To show an error message when a user/group name is not found, the SharePoint built-in user/group picker uses a span whereas I have used a label.

Figure 1: User/Group picker
After user/group name is entered in the text box, there are two ways to check if the user/group name is valid. One way is to press Enter from the keyboard, another is to click on Check Names. I have implemented the user/group name checking logic in the Check Names icon (the ValidateSharePointUser function in the code-behind page). When the Enter key is pressed in the textbox, with a JavaScript, I actually call the Check Names icon’s click event in the JavaScript function fetchUserName().
When the browse icon is clicked, a new screen appears, allowing users/groups to search. The browse button in the SharePoint built-in User/Group Searcher is actually an anchor link (an <a href…….> in HTML). In the Click event of the anchor, a JavaScript function is called. In my example, the function is _Dialog_UserField_browse. I have tried to mimic the actual SharePoint code. In this function, I have found that SharePoint uses the current site name to show the picker. So, I have taken a hidden control in my page and put the current site name in the page_load event. The URL for the picker, as I have found, is something like: \u002fSiteName\u002f_layouts\u002fPicker.aspx?........;.
I have found the link is fixed except the SiteName, which is the current site name. So, I need to put the site name in the link. That’s why I put the site name in the hidden control. But remember that, in the case of top level site (i.e., SPSite) the site name is empty, so the \u002fSiteName will be removed from the link as I have done in _Dialog_UserField_browse. Finally, in the _Dialog_UserField_browse JavaScript function, a dialog is called, as commonShowModalDialog, with three parameters. The first parameter, sDialogUrl, is the location of the picker window. The second parameter, sFeatures, is the settings of the picker window (i.e., width, title etc.). The third parameter, CallbackWrapper_User_Browse, is the callback JavaScript function which is to be called when the user closes the picker window.
So, in the CallbackWrapper_User_Browse function, I need to parse the result of the picker and put the user name in the textbox. The picker will return an XML (if the user is found) like below:
Collapse
<Entities Append="False" Error="" Separator=";" MaxHeight="3">
<Entity Key="ONIRBAN\sohel" DisplayText="ONIRBAN\sohel" IsResolved="True
Description="ONIRBAN\sohel">
<ExtraData>
<ArrayOfDictionaryEntry xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DictionaryEntry>
<Key xsi:type="xsd:string">DisplayName</Key>
<Value xsi:type="xsd:string">ONIRBAN\sohel</Value>
</DictionaryEntry>
<DictionaryEntry>
<Key xsi:type="xsd:string">SPUserID</Key>
<Value xsi:type="xsd:string">1</Value>
</DictionaryEntry>
<DictionaryEntry>
<Key xsi:type="xsd:string">PrincipalType</Key>
<Value xsi:type="xsd:string">User</Value>
</DictionaryEntry>
</ArrayOfDictionaryEntry>
</ExtraData>
<MultipleMatches />
</Entity>
</Entities>
I have used XML DOM to parse the return XML from the picker and put the username in the textbox.
When the user clicks on the Check Names icon, the server-side function ValidateSharePointUser is called, which checks if the user has permission to the site.

Using the Code

The project, along with this article, has a user control ctlUserGroupBrowser.ascx which has the user/group picker. To use the control, you need to use SmartPart from here. Download the SmartPart and install the web part. Then, compile the project and put the UserGroupBrowse.dll in the GAC. Now, add the following entry in the SafeControls section of the web.config:
Collapse
<SafeControl Assembly="UserGroupBrowse, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=af26021c4978ee97" Namespace="UserGroupBrowse"
TypeName="*" Safe="True" />
Then, add the following entry in the <assemblies> section of the web.config:
Collapse
<add assembly="UserGroupBrowse, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=af26021c4978ee97" />
Put the ctlUserGroupBrowser.ascx in the usercontrols folder of the port of the SharePoint site’s virtual directories. Go to the site, and add the SmartPart web part to the page. Finally, browse the ctlUserGroupBrowser.ascx control from the SmartPart toolpane.

AJAX Extension

When you use the control, the page will be refreshed as you click Check Names or press Enter in the text box. To get rid of this, you need to use the AJAX supported SmartPart. You can get the SmartPart with AJAX support from here. Also, you need to wrap:
Collapse
<div id="actionItemPanelDivision">
with:
Collapse
<asp:UpdatePanel ID="ActionItemPanel" runat="server">
<ContentTemplate>
Then, your control markup will be as shown below:
Figure2.JPG

SharePoint Object Browser

Introduction

This application is a SharePoint site object browser which shows all the contents of a SharePoint site in a tree structure. The main objective of this sample program is to show how to use a SharePoint object model. This sample code is a very easy view of SharePoint development. But to develop in SharePoint these are things a developer should know.

Background

There are lot's of samples and help for SharePoint administration and customization. But there are very few samples and examples in SharePoint programming. At the beginning, we really had to struggle to develop WebPart and to understand how object models and other SharePoint stuff works. I have been working on a SharePoint project for nearly one year and I felt like sharing some of my experiences with others using different sample applications. And this is my first example.

What this Application Does

This is a SharePoint site object browser application. In the textbox, followed by the label Site Address, enter a SharePoint site address and then press the Go button. You will see all subsites and content of subsites will be generated in a tree form in the TreeView control. In that control, if you click on a tree node of type list then the list's contents will be shown in the bottom DataGridView. In the Grid you will find all columns and rows of that particular list. Even some columns that you will see here, will not be visible from SharePoint site. You can also select a column from the DropDownList and can update the value for all rows for that particular column. But as I said, you will be able to see some SharePoint internal columns, and those values we cannot update.

Understanding the Code

We can take a SharePoint site instance (SPSite) from the site's URL. Then we can access that SPSite object's properties.
Collapse
uxBrowser.Nodes.Clear();
SPSite site = new SPSite(uxAddress.Text);
TreeNode rootNode = uxBrowser.Nodes.Add(site.Url);
uxBrowser.NodeMouseClick += new TreeNodeMouseClickEventHandler(uxBrowser_NodeMouseClick);

for (Int32 i = 0; i < site.AllWebs.Count; i++)
{
SPWeb web = site.AllWebs[i];
TreeNode webNode = rootNode.Nodes.Add(web.Name);
for (Int32 j = 0; j < web.Lists.Count; j++)
{                   
SPList list = web.Lists[j];
TreeNode listNode = webNode.Nodes.Add(list.Title);
listNode.Tag = list;                   
}           
}
As you can see, fist we are creating an instance of SPSite from a string (site URL) then we are getting AllWebs which is a collection of SPWeb objects. After that we loop through all SPWeb objects and its contents and extracting its information. While doing so, we are also adding these objects's names and references (saved in the Tag property) in the TreeView control to generate the tree.
Now if you click on the list type tree node, it will take the list reference from the Tag property.
Collapse
_CurrentSelectedList = ((SPList)e.Node.Tag);
Then the Fields property of _CurrentSelectedList will return the column collection of that list, and finally, _CurrentSelectedList.Items will return all rows (items) in that list. To make the data more presentable, I have added all contents in a DataTable then bound it to the DataGridView.
When the user clicks on the list type tree node, I am also assigning the DataTable as Data Source of the DropDownList. Now the user can select a column and update the column's value. But one problem may arise, while updating the list; if the user does not have permission to update then it will generate an error. This can be solved by impersonating the Sharepoint\system user by using the SPSecurity.RunWithElevatedPrivileges method. This is a technique to use Object Model with full privilege..
Collapse
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite ElevatedsiteColl = new SPSite(siteAddress))
{
ElevatedsiteColl.AllowUnsafeUpdates = true;
using (SPWeb ElevatedSite = ElevatedsiteColl.OpenWeb(webName))
{
....
}
}
});
Inbetween this method, the code will execute with an Administrative (Sharepoint\system) privilege. So we will be able to do any kind of read/update/delete operation.
In the code you may also have noticed that I am initiating SPSite, SPWeb (those are created repeatedly) in a using block. This is because SPSite and SPWeb is a very resource consuming object. So we have to make sure the instance gets disposed after its use.

WebParticles: Developing and Using Web User Controls as WebParts in Microsoft Office SharePoint Server 2007

Introduction

Visual Studio developers have enjoyed the speed and consistency of visual designers for controls since the pre-.NET days of Visual Studio. In the world of Microsoft Office Server 2007 Web Part development, developers have no visual designer available for the development of WebParts. This means dynamically loading controls or concatenating a large number of strings in order to render even the simplest controls. (One could also use XSLT, but that discussion is for another day). We are not quite ready to give up the intuitive and speedy development visual designers offer.
Visual Studio does offer the ability to design User Controls, including Web User Controls. But these controls cannot be used as SharePoint WebParts and personally, I want to do just that. This article will introduce the concept of creating distinct components (Web Particles) that together provide the full benefit of SharePoint WebParts while still allowing the use of the familiar and productive visual designers available to Web User Control developers. I refer to these components (tongue in cheek) as "WebParticles" since each one is just a portion of the functionality ultimately provided by the WebPart.

Overview

We will need to create a Visual Studio Web Application project, create a Web User Control (ASCX), a class that can act as the Web Part interface to our ASCX Web User Control and a ASP.NET web page in which we can test and debug our components.

Creating the ASP.NET Web Application

In Visual Studio, create a new ASP.NET Web Application (new web site will NOT work for this exercise). For the project name, enter SmartParticles*.
New Project
Since we are developing this part for SharePoint, we will need a reference to SharePoint.dll. If you are developing on a machine having MOSS or SharePoint Services installed, this file is typically located in the %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\12\ISAPI Directory. In my case the expanded path is C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.SharePoint.dll. If you are developing on a machine not having SharePoint or MOSS, you will need to copy this file along with Microsoft.SharePoint.Search.dll and Microsoft.SharePoint.Search.xml from the same directory to a directory on your local computer. In either scenario, select the Microsoft.SharePoint.dll and set a reference to it in your project. Visual Studio will include the proper files in your project output.
Add reference
Next, add a Web User Control file to your project and name it WebParticleControl.ascx.
Add new item
In the control designer, add three Textboxes, a drop down Control, a Label and two Buttons as follows:
Control Name Notes
TextBox Control txtFirstName
TextBox Control txtLastName
TextBox Control txtCity
DropDownList Control ddlState add a few items of your choice to this control
Label Control lblResults
Button btnSubmit Change Text property to "Submit"
Button btnReset Change Text property to "Reset"
I also created a table to organize the controls and labels for the text boxes, but that exercise is optional.
Table format
Double-click the Submit button to generate the stubbed-out btnSubmit_Click event handler in the code-behind file (WebParticleControl.ascx.cs). If you cannot see this file, ensure that "Show All Files" is toggled on in Solution Explorer:
Show all files
In the btnSubmit_Click event handler, enter this code:
Collapse
string _response = "Hello {0} {1} from {2}, {3}! Please reset the form!";
string szState = ddlState.SelectedValue; lblResults.Text =
string.Format(_response, txtFirstName, txtLastName, txtCity, szState);
Double-click btnReset to generate the Click handler and enter this code in the bntReset_Click handler:
Collapse
txtCity.Text = "";
txtFirstName.Text = "";
txtLastName.Text = "";
ddlState.SelectedIndex = 0;
Next, add a class file to your project named WebParticle.cs.
Add another class
To summarize this class, it will inherit from the Microsoft.SharePoint.WebPartPages.WebPart and override the CreateChildControls and RenderContents methods to load and render the ASCX Web Control we created in the preceding steps. This class will inherit from the Microsoft.SharePoint.WebPartPages.WebPart class, so you will need to add the correct using directive to your namespace or class section.
Collapse
using Microsoft.SharePoint.WebPartPages;
Set the inheritance of the class to WebPart:
Collapse
public class WebParticle: WebPart 
I have defined two properties which together determine the location from which to load the associated Web Control ASCX file. If you wish to simply inherit from this class, just override these property declarations, one of which defines the source directory and the other defines the filename hosting your control.
Collapse
protected string UserControlPath            = @"~/usercontrols/";
protected string UserControlFileName        = @"webparticlecontrol.ascx";
Next, the class will override the CreateChildControls method to load the Web Control. In this method, the control is loaded from the source file by the Page property inherited from System.Web.UI.Control via Microsoft.SharePoint.WebPartPages.WebPart. The Page property allows programmatic access to the underlying ASP.NET Page instance hosting our WebPart in SharePoint.
Collapse
protected override void CreateChildControls()      
{
try
{
// load the control ... this could require GAC installation

// of your DLL to avoid File.IO permissions denial exceptions

_control = this.Page.LoadControl(UserControlPath + UserControlFileName);
// add it to the controls collection to wire up events

Controls.Add(_control);
}
catch (Exception CreateChildControls_Exception)
{
_exceptions += "CreateChildControls_Exception: " + CreateChildControls_Exception.Message;
if (AlwaysBubbleUpExceptions)
{
throw;
}
}//end catch

finally
{
base.CreateChildControls();
}//end try/catch/finally block

}//end protected override void CreateChildControls()

Next, we will override the RenderContents method which is specific to the WebPart class from which we inherit. This method was chosen because in the life cycle of SharePoint web pages, by the time this method is called all prerequisite processing will have taken place, including the creating and assignment of SharePoint variables and the CreateChildControls method. There is no need to call EnsureChildControls here since child controls will always exist when this method is called by the SharePoint ASP engine.
Collapse
protected override void RenderContents(HtmlTextWriter writer)
{
// not much to do here except to programmatically and cleanly

// handle exceptions

try
{
base.RenderContents(writer);
}
catch (Exception RenderContents_Exception)
{
_exceptions += "RenderContents_Exception: " + RenderContents_Exception.Message;
if (AlwaysBubbleUpExceptions)
{
throw;
}
}
finally
{
if (_exceptions.Length > 0 && AutoWriteExceptions)
{
writer.WriteLine(_exceptions);
}
}//end try/catch/finally

}//end protected override void RenderContents(HtmlTextWriter writer)

Signing and Building the Project

We are not quite ready to build our class. Since we intend this WebPart and Web User Control to live in Microsoft Office SharePoint Server and the Global Assembly Cache, we will need to assign a Strong Name key and sign the control. In Solution Explorer, right-click the SmartParticles project node and select Properties. The Project Property Pages appear. Select the Signing tab from the choices on the left. Check the "Sign the assembly" box and select from the "Choose a strong name key file" drop down list.
Choosing a new strong name key file
Enter "SmartParticles.snk" in the "Key file name" field. Uncheck the box marked "Protect my key file with a password" unless, of course, you want to password-protect your key file (not a bad idea).
Create a strong name key file
Click "OK". The SmartParticles.snk Strong Name Key file is added to your project. Now, build the project using the Visual Studio Build menu.

Deploying your WebPart and Web User Control

Creating a SharePoint WebPart is relatively simple compared to deploying one. Since we are using the WebParticle approach, we have to deploy both an ASCX file and the compiled DLL that contains the supporting class for the ASCX Web User Control and the class that will actually be the SharePoint WebPart. Here is a summary of what we need to do in order to deploy our WebParticles:

Summary

  • Compile the project
  • Copy the ASCX Web User Control to your /UserControls/ directory (or your selected directory)
  • Copy the compiled DLL into the Global Assembly Cache
  • Discover the publicKeyToken property of our assembly
  • Add the appropriate SafeControl entries for each of our classes in SharePoint's web.config file
  • Add an assembly element to the assemblies section of SharePoint's web.config file
  • Create a SmartParticles.WebPart XML file with necessary information for deployment to SharePoint
  • Upload the SmartParticles.WebPart XML file to SharePoint's WebPart gallery
  • Test the part's installation

Compile the project

Use the Visual Studio Build menu to build your project.

Copy the ASCX Web User Control to the /UserControls/ directory (or your selected directory)

First you will need to ensure that your target SharePoint web site has an UserControls directory. If not, create it. Then copy the ASCX file from your project directory to your SharePoint UserControls directory.
copy the file

Copy the compiled DLL into the Global Assembly Cache

The Global Assembly Cache (GAC) is a special folder located at %WINDIR%\Assembly where %WINDIR% is the full path to your Windows folder (such as C:\Windows or C:\Winnt). Use Windows Explorer to copy your DLL into the GAC folder.

Discover the publicKeyToken property of our assembly

Remember adding a Strong Name Key to our project? The result of this is that our Assembly is strongly named, meaning is has a Public Key token. Microsoft came up with this strategy to combat "DLL Hell" that used to plague COM/COM+ Developers back in the day. If you've never heard of DLL Hell, it means that Microsoft has done a very good job in their efforts to make our lives easier. I'm not complaining, but there is one more thing they could have done for developers: give us the ability to view our project's public key token directly in Visual Studio. Maybe my next project will be an add-in... Anyway, there are two ways you can discover your DLL's public key token. Since we copied our assembly into the GAC, the public key will be plainly visible to us if we look. Just use Windows Explorer to browse to your C:\Windows\Assembly folder (or %WINDIR%\Assembly if Windows is not installed in the default location). Scroll down and find the SmartParticles assembly:
In the gac
As you can see, our version information and Public Key Token are plainly visible. Still, you will have to copy it into a text file by hand for our next step. Alternatively, you can use .NET Reflector by Lutz Roeder at http://www.aisto.com/roeder/dotnet/ to browse to your assembly's DLL file and read out the Assembly information and Public Key Token with no hassles and the ability to cut and paste.
.NET Reflector really rocks!
If you built the project with the Strong Name Key included with the source code, you have it easy: just copy the lines below onto your clipboard.
Collapse
SmartParticles, Version=1.0.0.0, Culture=neutral,PublicKeyToken=8e2900508c69349a
We have two tasks that require this information. First, we must let SharePoint know that our control is Safe. To do this, we will need to edit the web.config file of our SharePoint site. Use your favorite text editor to browse for and open your site's web.config file. You will see a section named "SafeControls" with a number of default entries provided by Microsoft. You will need to add the following entries under "SafeControls":
Collapse
<SafeControls>

....various Microsoft entries.....

<Assembly="SmartParticles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8e2900508c69349a"
Namespace="SmartParticles" TypeName="WebParticle" Safe="True"/>
<SafeControl Assembly="SmartParticles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8e2900508c69349a"
Namespace="SmartParticles" TypeName="WebParticleControl" Safe="True"/>
<SafeControl Assembly="SmartParticles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8e2900508c69349a"
Namespace="SmartParticles" TypeName="*" Safe="True"/>

</SafeControls>






Replace the PublicKeyToken with the token from your assembly (if you did not use the included StrongNameKey file).

Add an assembly element to the assemblies section of Share Point's web.config file

You would think that would be enough but, no, SharePoint still does not know enough about your types to load them. It does not check the SafeControl section until it loads the Assembly using Reflection. First, it must understand how and where to load your assembly. You could place your assembly in your Share Point's bin folder, but then you would have two copies to update each time you built or modified your assembly. Best to leave it in one place, the GAC, and keep things simple. The way to do this is to tell SharePoint about your assembly and the way to do that is to add an assembly reference to the web.config file. Every ASP.NET web.config file has a compilation section, and SharePoint is no exception. Find the compilation section of your SharePoint site's web.config file. Beneath it you will see an assemblies section with at least an entry for SharePoint beneath it. Add a node for your assembly using the same information from the assembly that you discovered earlier:
Collapse
SmartParticles, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8e2900508c69349a
Here are the entries, replace the public key token if needed.
Collapse
<compilation batch="false" debug="false">
<assemblies>
<add assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c" />
<add assembly="SmartParticles, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=8e2900508c69349a" />
</assemblies>
</compilation>

Create a SmartParticles.WebPart XML file with necessary information for deployment to SharePoint

A WebPart xml file is a very simple, structured text file with the minimum information needed to add your WebPart to the WebPart gallery in SharePoint. Use Visual Studio to add an XML file to your project. Name the file SmartParticles.WebPart:
Add another new item
Paste the following code into your XML file:
Collapse
xml version="1.0" encoding="utf-8" ?>
<webParts>
<webPart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="SmartParticles.WebParticle, SmartParticles, Version=1.0.0.0,Culture=neutral,
PublicKeyToken=8e2900508c69349a" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string">SmartParticles Web Part</property>
<property name="Description" type="string">A demonstration using WebParticles in
a SharePoint WebPart</property>
<property name="ChromeType">TitleOnly</property>
<property name="ChromeState">Normal</property>
<property name="ItemLimit" type="int">15</property>
<property name="ItemStyle" type="string">Default</property>
</properties>
</data>
</webPart>
</webParts>
WebPart files can be much larger and complex, but this simple file illustrates our simple web part. The sections that are important for our demonstration are the type section and the Title and Description property sections. In the type name section, you must enter the name of your WebPart class, in this case SmartParticles.WebParticle, followed by the assembly information we have already copied twice into web.config. You can put any strings you want into the Title and Description properties. The string that is in the Title property becomes the default title for your WebPart when it is added to a SharePoint page. Save your changes and close the file.

Upload the SmartParticles.WebPart XML file to Share Point's WebPart gallery

Next, we need to import (or upload) into SharePoint the WebPart file we created in the previous section. You will need to be a SharePoint administrator to perform this task. If you have a dedicated SharePoint Administrator upon whom you can offload this task, you are lucky. If not, browse to your SharePoint site. Under "Site Actions" select Site Settings, Modify All Site Settings.
Modify all site settings
On the Site Settings page, under Galleries, click Web Parts
uploading the part
In the Web Part Gallery, click Upload, then Upload Document:
Uploading the part
In the form that appears, browse to your Project folder for your SmartParticles.WebPart file, then click Upload to upload it. When it has uploaded, the Web Part Gallery Edit Item page is displayed. You will see (and can change, if you like) the information entered into your WebPart XML file. In the Group section, I recommend added your WebPart to a non-Default group to make it easier to find. There are a lot of WebParts that come with Microsoft Office SharePoint Server 2007 directly out of the box!
Testing the installation of your part
When you are done, click "OK". You will be returned to the Web Part gallery where you will see that your part has been installed. It will be decorated with the "New!" splash.
Newly installed part

Test the part's installation

You can now test that your WebPart is installed by clicking its name (as shown in the preceding figure). This will take you to the Web Part Preview page. Here, as the name implies, you can preview your part; you cannot test your Web Part's functionality in the Web Part Preview page. For example, if you click the buttons in the Preview, the page will reload and nothing else will happen. Just thought I would let you know so you wouldn't freak out about it.
Testing the installation validity
If your WebPart blew up or would not install, verify that you followed all of the procedures in order before wailing and gnashing your teeth (or contacting your humble narrator). Don't worry, there is a short, but hopefully effective, troubleshooting guide near the end of this document.

Using your WebPart

To test or use your WebPart, you will need to add it to a SharePoint page just like you would any other WebPart. This will be very simple since we have added our WebPart to the Web Part Gallery. To summarize:
  • Edit a SharePoint page
  • Select a zone into which you want to place your WebPart
  • Add the WebPart to the zone
  • Save the page
This is what SharePoint is all about. So easy a caveman user can do it! [would have put a caveman graphic here, but do not like lawyers banging on my doors]

Edit a SharePoint page

Under site actions, select Edit Page.
Edit the page
Click on a zone and select "Add Web Part". The Add Web Part dialog will be displayed:
There it is
Scroll down and find the SmartParticles Web Part, select it and click "Add". Publish your page so everyone can see it. Your web part will now be fully functional on your SharePoint page.

"Hello, Dude!"

Hello, Dude!
* Yes, it is a take-off on SmartPart, the excellent tool for SharePoint created by Jan Tielens, et al.

Troubleshooting

Access Denied or "File.IO" Permissions exceptions

If, like me, you run your Visual Studio from My Documents, when you copy files from this location on an NTFS partition using Copy and Paste in Windows Explorer, you also copy the ACL (Access Control List) with these files. Files in My Documents, including these, are not accessible by SharePoint. When you copy files from this location into your SharePoint site directory if they are both on the same volume (logical drive such as C:\), the permissions will also be copied and SharePoint will not be able to load either the DLL or the ASCX files. You will get the ubiquitous "Access Denied" message in SharePoint which is not very helpful. For more information about ACL copy problems, see http://support.microsoft.com/kb/320246. Fortunately, there are a couple of easy workarounds. The easiest is to work on a separate volume such as another hard drive. Alternatively, copy the ASCX to another hard drive and then to your SharePoint directory of choice. You may only want to do this if you are getting the Access Denied error. Then again, better to prevent than solve problems.

Cannot load type Assembly.TypeName

Be sure you added an assembly reference to your assembly in Share Point's web.config file. Did you add your assembly to the GAC? If you did both of these things, try adding your assembly to the bin folder of your Share Point site.

Cannot import the WebPart Exception

Verify that you have added a SafeControl entry in Share Point's web.config file. See "Access Denied or File.IO Permissions exceptions".

Nothing happens when you click your control's buttons

Ensure that this line is present in your Class's CreateChildControls method.
Collapse
Controls.Add(_control);