With SharePoint 2010 you can now extend the out of the box web parts, which essentially means you can create a new web part that inherits from one of the out of the box ones. In this post, I demonstrate extending a SharePoint Web Part in depth, using the search box as an example. First, let's take a look at the search box web part.
Find the Class
Since we will be inheriting from this web part, the first question we need to answer is: What is the class name of the web part I'm trying to extend? The answer isn't straightforward. The SharePoint Web Part Gallery doesn't provide this information, so it's not readily apparent by looking at the web part in design mode.
One way to find out is to add the web part to a page. In this case, from the Web Part gallery select the web part "Search Box" from the Category "Search". On the upper right corner of the web part, click on the drop down arrow and select "Export..."
This will prompt you to save the Web Part Definition file (.dwp). Open this file in a text editor and look for these two XML elements: Assembly and TypeName. In our case, the values are:
<Assembly>Microsoft.Office.Server.Search, Version=18.104.22.168, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
This tells us a few things:
- The class name for this web part is SearchBoxEx, which is what we have to inherit from.
- It resides in the Microsoft.Office.Server.Search assembly.
- It's part of the Microsoft.SharePoint.Portal.WebControls namespace.
You can confirm this by looking at the SearchBoxEx documentation. We have two namespaces involved here because SearchBoxEx is implemented in Microsoft.Office.Server.Search, but it inherits from Microsoft.SharePoint.Portal.WebControls.WebPartLoc. With a little digging around, I found that these two namespaces are in:
Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.Office.Server.Search.dll
Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\microsoft.sharepoint.portal.dll
As it happens, these are not listed in the .NET tab of the "Add Reference" dialog in Visual Studio, so you will have to browse for them manually.
Create the project
Create a new project using the Empty SharePoint Project template and add a new Web Part to it. I called mine SearchBoxExtension. Your class definition should look like this:
public class SearchBoxExtension : WebPart
As with every inherited web part, start by calling base.CreateChildControls:
protected override void CreateChildControls()
Add the assembly references using the Browse tab to locate the two DLLs. Your references should look like this:
Inherit your new web part from Microsoft.SharePoint.Portal.WebControls.SearchBoxEx (the TypeName value) instead of WebPart:
public class SearchBoxExtension : Microsoft.SharePoint.Portal.WebControls.SearchBoxEx
Build and deploy your project and try to add your new web part to a SharePoint page. You should get this error:
.dwp vs .webpart
What's the problem? Here's what just happened. Both .dwp and .webpart file types are XML web part descriptors that are deployed with your web part. The Dashboard Web Part (.dwp) format was used in earlier versions of SharePoint, where web parts inherited from Microsoft.SharePoint.WebControls.WebPart. The newer .webpart format, which supersedes .dwp, is what you use when you inherit from System.Web.UI.WebControls.WebParts, which is what you should always do when developing brand new web parts. For this reason, when you create a new web part in Visual Studio 2010, it automatically creates a .webpart descriptor for you:
SharePoint 2010 comes with a mix of older and newer web parts, so the descriptors that go with them might be either .dwp or .webpart. As you might've guessed from its namespace, Microsoft.SharePoint.Portal.WebControls.SearchBoxEx is one of the older ones and therefore requires a .dwp descriptor. The error we just got is therefore telling us that it doesn't like SearchBoxExtension.webpart.
Create the .dwp descriptor
So how do we get the .dwp file?
There are two ways:
- Create it manually
- Modify the .dwp exported from the original class
To create it manually, use SearchBoxExtension.webpart for reference. First, add a new XML file to your web part and give it the same name but with a dwp extension. Your web part folder should look like this:
Corey Roth has a nice post that compares the differences between the two formats. First, let's look at SearchBoxExtension.webpart:
<?xml version="1.0" encoding="utf-8"?>
<type name="SearchBoxTest.SearchBoxExtension.SearchBoxExtension, $SharePoint.Project.AssemblyFullName$" />
<property name="Title" type="string">SearchBoxExtension</property>
<property name="Description" type="string">My WebPart</property>
By looking at the differences between the two formats, mapping the values from one to the other was relatively straightforward. Let's look at the result first:
<?xml version="1.0" encoding="utf-8"?>
XML schema differences aside, there are essentially two changes. First, the xmlns is http://schemas.microsoft.com/WebPart/v2 instead of http://schemas.microsoft.com/WebPart/v3 indicating our move to an older format, and second, we need the assembly's public token. To get the public token, use the strong name tool with the -T parameter (sn.exe -T), or use Kirk Evans' cool trick using Visual Studio External Tools.
Alternatively, you can use the .dwp that you exported at the beginning of this exercise. Follow the steps above to create a new XML above and copy the contents of the original .dwp into your new one. Then make the following changes:
- In the WebPart root element, remove all but the xmlns attribute.
- Set the Assembly name to $SharePoint.Project.AssemblyFullName$ (you can copy this from the .webpart file)
- Set the Assembly version to your assembly's version. This is usually 22.214.171.124, but you can find it in AssemblyInfo.cs in your project.
- Replace the PublicKeyToken as described above.
- Replace the TypeName with the type name provided in your .webpart file.
Next, we have to ensure the .dwp file is deployed with the web part. Click on the file in Solution Explorer and change its Deployment Type property from NoDeployment to ElementFile. You can now safely delete the .webpart file. Your web part folder should now look like this:
Finally, edit Elements.xml and replace both instances of .webpart with .dwp in the Elements/Module/File element. Build and deploy your project and add your web part to a SharePoint page. You should see the default search box:
The web part you just added to your test page may not look exactly like the original. If you created your .dwp from scratch, you will have ignored all the other properties that had been set in the .dwp for the base class. If you modified the original .dwp, you will have retained the other parameters that defined the web part's default configuration.
You are now ready to build your derived search box.