WSS 3.0 webparts development
What’s new for for webpart developers in WSS 3.0
There are two important things, what developers must know:
1) Webparts for WSS v2 in most cases fully compatible with WSS 3.0 without recompilation (and .cab repacking) in RTM version of WSS 3.0/MOSS2007
2) New webpart framework model for WSS 3.0 based on ASP.NET 2.0 webparts and is not compatible with WSS v2
Differences Between WSSv2 and ASP.NET Parts
SharePoint version 3 has made a significant bet on ASP.NET web parts as the preferred mechanism for delivering web parts.
In version 3, a developer has three choices for how they wish to develop web part:
- create a SharePoint web part. A SharePoint web part derives from the Microsoft.SharePoint.WebPartPages base class. These web parts will be referred to as “WSS.WebParts.”
- create a “pure” ASP.NET 2.0 web part. This is a web part that derives from the base Whidbey base class. These will be referred to as “ASP.WebParts”
Note that in version 3 WSS.WebPart derives from ASP.WebPart, so technically, WSS.WebParts are ASP.WebParts. However, for the purposes of discussion when the term ASP.WebPart is used we will refer to “pure” web parts.
The long term vision for SharePoint is to solidly bet on ASP.NET 2.0 as the owner of the web part framework. Therefore, a goal of this vision is to ensure that SharePoint does not deviate from the core web part framework; that developers can place a solid bet on ASP.NET 2.0.
However, in SharePoint version 3 there will remain some core differences between WSS.WebPart and ASP.WebPart that developers should be aware of:
- WSS.WebParts support client side connections; ASP.WebParts do not.
- WSS.WebParts support a PartCaching infrastructure; ASP.WebParts do not
- WSS.WebParts have a facility for storing data that a web part might need to reuse. This is contained within the PartCache* functions on the WSS.WebPart base class. ASP.WebParts do not have this functionality. A developer would need to implement the IPersonalizable interface and store data, and develop their own time stamping scheme to ensure that data is invalidated. Alternatively, a part could use in memory or session state to track web part data.
- WSS.WebParts requires that all properties be Xml serializable. ASP web parts use TypeConverter infrastructure to seralize.
- AllowCustomization and AllowPersonalization properties are enforced at UI level only
In SharePoint version 2, if these properties were set to true than customization or personalization of a web part was blocked at both the user interface and the object model level. Whidbey only enforces these settings at the user interface level. SharePoint version 3 now follows this model.
Differences in How "Pure" ASP.NET web parts work vs. Other ASP.NET implementations
For ASP.NET Web Parts hosted in WSS, there are some behavior differences vs. how other ASP.NET servers might deal with the parts.
Developers need to explicitly call SetPersonalizationDirty to cause their web parts to have changes persisted, when hosted in WSSv3.
On other ASP.NET 2.0 implementations, changes to certain properties will automatically get persisted. When the web part is hosted within WSS, developers will need to call
if (null != WebPartManager) SetPersonalizationDirty()
to ensure their properties are persisted.
Developing ASP.NET Web Parts
There are two fundamental web part frameworks supported in WSS: the WSS v2 Web Part Framework (Microsoft.SharePoint.WebPartPages.WebPart) and the ASP.NET 2.0 Web Part Framework (System.Web.UI.WebControls.WebParts.WebPart)
For most new web parts going forward, developers should use the ASP.NET 2.0 framework.
To develop an ASP.NET web part for WSS, you need to do the following things:
Develop an ASP.NET Web Part Assembly
Developing a web part assembly typically means creating a class library with a class that derives from the System.Web.UI.WebControls.WebParts.WebPart base class.
A simple way to do this is:
1. Start up Visual Studio 2005
2. Start a new class library project
3. Add a reference to System.Web
4. In your .cs file, paste in the following:
using System;
using System.Text;
using System.Web.UI.WebControls.WebParts;
namespace MS.Samples
{
public class ASP.NETHelloWorldPart : WebPart
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write("Hello, ASP.NET!");
}
}
}
5. Compile this -- you should have an assembly which contains your Hello World web part.
For more information on developing ASP.NET assemblies, the ASP.NET 2.0 documentation is a great place to start.
NOTE: One caution on this. ASP.NET has a capability for hosting 'plain' controls as web parts, and optionally exposing an interface (IWebPart) so that those controls can take advantage of web part features. As a result, you will see controls and .ascxs acting as Web Parts. WSSv3 does not support this capability; your web part must derive from the WebPart class directly.
Place your assembly in the bin or global assembly cache
There are two fundamental locations to deploy an assembly to, within SharePoint:
1. The Bin Directory
2. The Global Assembly Cache
Each has its own pros and cons.
As a positive, the Bin Directory is a partial trust location. By default, code that runs from this directory has a very low level of code access security (CAS) permissions. It is the job of an administrator to specifically and explicitly raise the permissions granted to a web part so it can function properly. Because of this level of control and defense-in-depth, administrators tend to prefer that assemblies they get can run in the bin directory, with a known set of required CAS permissions.
The Bin directory is also per-web application. Depending on your scenario, this is either an advantage or disadvantage. This makes it possible to isolate code to a particular web application. As a negative, if you want your web part to run everywhere, you would need to deploy your bin assembly.
The bin directory is a folder stored off your web application root.
The global assembly cache is a global place where signed assemblies can be deployed. These assemblies run with full trust by default. They are globally installed, so they will work in any web application. As mentioned in the bin directory, there are generally no CAS restictions on code installed to the GAC; therefore, you lose the defense in depth security benefit.
One negative is that deploying your PDBs to GAC'ed assemblies can be a little tricky to setup.
ASP.NET Web Parts in the Bin directory
ASP.NET parts in the bin directory have some special constraints for security.
The bin directory is a partial trust location -- when your part is executed, you do not have full trust code permissions.
Because the code that calls into your part will be partial trust, your ASP.NET part needs to have the "AllowPartialTrustedCallers" attribute set on it. This can be done at the assembly level.
WARNING: Marking an assembly as safe to AllowPartiallyTrustedCallers puts a lot of responsibility for safe implementation on the developers.
Another issue is that the code access security permissions for the bin directory are very low by default -- only pure execution is allowed.
You almost certainly will need to elevate these permissions to have your assembly run correctly.
There are two ways to do this:
1. Inside of web.config in the web application root you will see a tag called trust with an attribute as level="WSS_Minimal". You can change this to WSS_Medium. This will raise the net trust level of the bin directory.
2. Create a new trust policy file, and point your web.config at that.
#1 is simpler, but because it generically raises the trust level by granting arbitrary new permissions you might not need, it is less secure.
#2 is more complicated, but lets you have a more precise attribution of permissions for your parts.
Add your web part to the SafeControls List
A fundamental assumption of SharePoint is that 'untrusted users' can upload and create ASPX pages within the system. Not only should those users be prevented from adding server-side code within those pages, but there should be a list of approved controls those untrusted users can use. Put another way, just because you have the "FormatYourHardDrive" control on your machine doesn't mean that untrusted users should be able to use it.
Along with other defense in depth strategies, one tool to prevent this is the SafeControl list.
The Safe Controls list is a SharePoint-specific list of controls and web parts that are safe for invokation on a page. The list is stored in web.config in your web application root.
To add a safe control entry, open up web.config and add a safe control entry for your custom assembly. You should copy one of the existing references and use that as a template.
Create a webpart file for your web part
Every web part should have a .webpart file -- a blurb of XML which describes the web part and shows up in the gallery.
The easiest way to create a .webpart file is to have WSS do it. After you have deployed your web part and registered in the safe control list, visit https://myserver/_layouts/newdwp.aspx. From there, select your web part class and select "Populate webpart gallery". This will create your new .webpart file.
Note that in beta there are some bugs with this process.
Add your web part to a page
Via provisioning, you can add a web part to the page by adding <View> tags (for list views) or <AllUsersWebPart> tags (for all other web parts) as a child of the <File> tag. You can only use these tags for pages you "own". If you want to add a web part to a page that is a part of someone elses' feature or site definition, you should use the object model to add it.
You can programmatically add a web part by calling SPFile.GetLimitedWebPartManager(), and from there, calling AddWebPart.
Developing WebParts using Sharepoint Services 3.0 Visual Studio 2005 Extensions
It way simple to develop for WSS 3.0 using webpart template for VS 2005. This extension contains the following tools to aid developers in building SharePoint applications:
Visual Studio 2005 Project Templates
- Web Part
- Team Site Definition
- Blank Site Definition
- List Definition
Visual Studio 2005 Item Templates (items that can be added into an existing project)
- Web Part
- Custom Field
- List Definition (with optional Event Receiver)
- Content Type (with optional Event Receiver)
- Module
SharePoint Solution Generator
- This stand-alone program generates a Site Definition project from an existing SharePoint site. The program enables developers to use the browser and Microsoft Office SharePoint Designer to customize the content of their sites before creating code by using Visual Studio.
HINT: Web Part template delivers some extremely useful features like automatic deployment and solution generation (former manifest).
You can download beta of this extension from https://www.microsoft.com/downloads/details.aspx?familyid=19F21E5E-B715-4F0C-B959-8C6DCBDC1057&displaylang=en
Differences in Behavior of ASP.NET Parts Hosted in WSS
Regrettably, there are some cases where how WSS works with "pure" ASP.NET web parts will differ a little bit from how a "vanilla" ASP.NET server would work with an ASP.NET web part. This topic documents a few of those cases.
IPersonalizable and "Dirty Behavior"
ASP.NET has infrastructure to automatically detect when changes have been made to properties. For example, if you change part.Title to some other value, it can recognize under the covers that the part's data stream has changes and make appropriate updates.
Because of differences in the way WSS stores data, however, we don't have the necessary plumbing to automatically detect changed properties in all cases. Therefore, in cases where you update the value of a property you should call .SetPersonalizationDirty() to inform the underlying infrastructure that the state of a property has changed.
IPersonalizable.Load()
IPersonalizable.Load is called before the web part is added to the web part manager. For this reason, the WebPartManager property will be null during load.
IPersonalizable.Save()
In some cases in ASP.NET, IPersonalizable.Save() is called. For example, during Import, IPersonalizable.Save() is called even if the web part returns false for .Dirty. In other cases, however, ASP.NET is a bit more efficient and does not call IPersonalizable.Save() if the web part returns false for .Dirty.
However, WSS needs to regenerate the property data on saving a web part. For this reason, when any particular web part property has changed (e.g., the Title), we will call into the Web Part's Save method to extract IPersonalizable data.
The implication of this is that web parts who implement IPersonalizable.Save() should be prepared to do work even if they return IsDirty = false. This is true in both the ASP.NET and WSS cases. In the WSS cases, though, it will be more often be true that .Save() gets called even if .IsDirty returns false.
Differences in Behavior When WebParts are Accessed from the WSS Object Model
The Windows SharePoint Services object model provides facilities for letting aribitrary code enumerate and interoperate with web parts. This object model could be called from command line executables, for example, where facilities such as ASP.NET's HttpContext and HttpRequest objects are not available. For this reason, when your web part is accessed "from the WSS object model", certain expecations you may have about objects being present may not hold up.
This is a list of limitations and things you should be aware of:
- WebPart.WebPartManager will be null
Based on the implications of this, you should ensure that for some operations (like IPersonalizable.Save()) you have a means of saving and persisting data even if the web part manager is not defined. Failure to persist data even if WebPartManager is null could result in data loss.
Hybrid Web Parts
General Philosophy
Hybrid web parts let you use “modern” ASP.NET web part development techniques and capabilities combined with base Windows SharePoint Services capabilities.
The general design is to, wherever possible, make implementing a hybrid web part operate like a “vanilla” ASP.NET web part.
Creating a Hybrid Part
To create a hybrid web part, one derives from Microsoft.SharePoint.WebPartPages.WebPart.
Usage of certain features will automatically make your web part a Hybrid Web Part:
- Implements IPersonalizable
- Uses the ASP.NET Personalizable attribute
Also, if your web part does not contain any XML serialization attribute hints, we will consider it a Hyrbid Web Part.
Restrictions on a Hybrid Part
Hybrid parts can not:
- Return toolparts via the GetToolParts method. They must use ASP.NET's CreateEditorPart function
Hybrid parts can have:
- Xml serializable properties but they won’t be used when we try to persist the Web Part. For that each personalizable property will need an applicable type converter.
Windows SharePoint Services Facilities you can use in a Hybrid Part
- Web Part Caching (e.g., SharePoint based caching methods, like PartCacheWrite/PartCacheRead/PartCacheInvalidate)
- V2 Web part connection interfaces, including client side connection capabilities and cross page connections
- Asynchronous features of web parts (work items)
ToolParts with Hybrid
Toolparts are not automatically injected for Hybrid webparts (this is only done for ASP.NET WebParts to simulate the pure ASP.NET developer experience where there might be toolparts inside the ZoneTemplate on an EditorZone on an ASP.NET page.)
So, for Hybrid Parts:
We will always call GetToolParts and CreateEditorParts for Hybrid Parts.
We will call CreateEditorParts and inject toolparts for ASP.NET parts.
Troubleshooting Web Parts
Ensure your web part is on the safe control list
Every web part needs to be on the safe control list. To add a web part, get the assembly strong name. From there, add this into the Safe Control list. The safe control list is stored in web.config in the root of your web application. The <configuration>/<SharePoint>/<SafeControls> XML section contains a list of assemblies which have controls that have been marked as safe. Copy an existing tag, and modify it as appropriate for your assembly.
Note: Even if you have added your assembly, it doesn't hurt to double check to ensure that the assembly name within web.config matches the current strong name of your compiled assembly.
Consider turning on callstacks
SharePoint by default swallows callstacks generated by web parts. You may want to expose these. To do this, open the web.config in the root of your web application. Set the Callstack attribute of the <configuration>/<SharePoint>/<SafeMode> tag to true. You may also want to turn off customer errors, under <configuration>/<system.web>/<customErrors>
For ASP.NET Web Parts, either support APTCA or place them in the GAC
ASP.NET web parts stored in the bin directory of a web application require that the AllowPartiallyTrustedCallers attribute flag (APTCA) be set for the assembly. WARNING: this flag has a number of securtiy implications so be sure to understand what APTCA implies. You may want to consider -- at least for debugging purposes -- placing your assembly in the GAC, In general, placing assemblies in the GAC for debugging purposes can help to narrow down problems.
Use the toolpane to catch error messages
In beta builds, the web part adder popup does not properly show error messages when a web part fails to add successfully. For this reason, you should use the toolpane to add your web parts. To use the toolpane, open the web part adder and select the "Show the toolpane" link at the bottom of the page. From the toolpane, drag and drop web parts onto the page.
Debug your web parts
You can use Visual Studio 2005 to debug your web parts. First, ensure that wherever your web part assembly is deployed to (either the GAC or the bin directory) has its PDB located next to it. If your part is GACed, you will need to go to %WINDIR%\Assembly and do a search for where your web part DLL is. Copy the PDB to that folder. Likely, you will want to set up a batch file to automate this process.
Every time you want to debug, go to the Debug Menu | Attach to Process. You should attach to the w3wp.exe process (you may need hit your website to ensure w3wp is running, and select "Show Process from All Users" to ensure it shows up in the list).
HINT: If you don’t want manually attach to w3wp every time, provide executable url for webpage which your webpart resides via Solution Properties/Debug/Start Browser with URL, and start debugging using F5 key.
Ensure your .webpart or .dwp file is correct.
Incorrect XML may be causing your web part to fail to import or export. The best thing to do is to let SharePoint create your .webpart/.dwp file for you, so you have a wellformed .dwp/.webpart file to compare and contrast with. To do this, (assuming you have site collection adminsitrative rights to your SharePoint site)
- Visit your SharePoint Home Page
- Site Actions Dropdown/Select Site Settings
- Click "Web Parts"
- Click New
(NOTE: Your web part class should show up. If it doesn't, that may be due to a failure to load the assembly (or the assembly might not be on the safe controls list.) - Select your classes and click "Populate Web Part Gallery"
- Click on the web part .dwp or .webpart file
- Click Export
Now, compare and contrast that .webpart/.dwp file to your own to ensure that you are not missing anything.
Consider upping the trust level of the application.
Office12 beta builds do not have finalized code access security settings. Therefore, depending on where you place your web part (bin vs. global assembly cache) you may experience issues where your code does not have enough rights to run properly. This may be the case even if your assembly is in the GAC (i.e., has full trust). You may want to try bumping up the trust level to full to see if this makes your issues go away. To do this, change your trust level to FullTrust. The current trust level is stored in web.config in the root of your web application. Find the <configuration>/<system.web>/<trust> tag, and change the "level" attribute to "Full".
Customizing Web Part UI
The web part user interface can be customized in a number of ways:
Customizing the "Add Web Part" popup
The "Add Web Part" popup is not highly customizable. However, it is possible to "suggest" which web parts the Add Web Part dialog should recommend on a zone by zone basis. To do this, you can declare a string on your zone called "QuickAdd-GroupNames". Any web part which has a corresponding match in its QuickAddGroup property will show up as a recommend part in this dialog.
You can also determine whether lists and libraries should show by adding the QuickAdd-ShowListsAndLibraries="true|false" to your web part.
Note that the web part gallery is a standard document library, and supports per-item permissions. You could use these per-item permissions to only allow a certain group of users to "read" a particular .webpart or .dwp file, and thereby "target" it to just those users. Keep in mind that this isn't a "web part security" feature, as anyone who can add web parts can upload arbitrary .webpart/.dwp files via the Import UI.
Customizing ToolPanes
Toolpanes can be customized in a number of ways. A web part by itself can declare custom toolparts which show up in the toolpane by overriding the GetToolParts method (WSS WebPart) or CreateEditorParts (ASP.NET WebPart).
A developer can also customize the toolpane generically by supporting the ICustomizeToolpane interface (which allows you to redefine the structure of the toolpane UI) or supporting IAddToGallery (which allows you to add new gallery "tabs").
Customizing Web Part Availabilty
With the addition of per-item security to SharePoint document libraries, it is now possible to assign individual permissions to web part definitions in the site collection web part gallery. This lets you control which people see which kinds of web parts. Note that this is not a security feature -- any user who can add web parts can import arbitrary web part definitions, even if you don't expose that web part in a web part gallery.
Customizing the Location of the Web Part Pane
On most SharePoint pages, we will append a toolpane as a child of the form tag, and add it in. However, if you wish to have a custom placement of the web part toolpane, you can accomplish this by adding a control into the page with an ID of "MSO_ContentDiv".
Using the "Quick Add Groups" feature of add web parts you can provide "strong suggestions" in the primary user interface (the add web part popup) for users. Ultimately the "Advanced Web Part Gallery" will show all available web parts.
Beyond this, there is no really good way to customize web part exposure in the gallery on a page by page basis. One option is to remove the web part toolpane altogether by deriving your page from something other than Microsoft.SharePoint.WebPartPages.WebPartPage. WebPartPage-based pages have the WSS web part toolpane always autoinserted, so by deriving from some other page class you can define an alternate "add web part" experience. There isn't a good example of this at this point, and likely the work to do this would likely be pretty complex.
Web Part File Localization
Web part definitions inside of the web part gallery inside of sharepoint are inherently monolingual. The root site of a site collection is in a particular language (e.g., Spanish) and so the web part definitions (.webpart files, etc.) in the web part gallery are created in that language (Spanish).
Now, if you are defining a SharePoint Feature or site definition, you can use resource tokens such that when the .webpart file is provisioned into that web part gallery, Therefore, the .webpart file you ship is resource pluggable, even if it ultimately gets provisioned into the web part gallery in a specific language. MOSS ships their web part files this way: if you take a look at the MOSS install, and look at the SearchWebParts feature (12\TEMPLATE\Features\SearchWebPart), you’ll see something like the SearchBestBets webpart file: Note the $Resources tag: it specifies that resources from 12\Resources\spscore.culture.resx (where culture is en-us, say) and the name of the resource to be used.
<?xml version="1.0" encoding="utf-8"?>
<webParts>
<webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
<metaData>
<type name="Microsoft.Office.Server.Search.WebControls.HighConfidenceWebPart,Microsoft.Office.Server.Search,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" />
<importErrorMessage>Cannot import this Web Part.</importErrorMessage>
</metaData>
<data>
<properties>
<property name="Title" type="string">$Resources:spscore,SearchBestBetsWP_Title;</property>
<property name="Description" type="string">$Resources:spscore,SearchBestBetsWP_Desc;</property>
<property name="ChromeType">None</property>
<property name="AllowMinimize" type="bool">true</property>
<property name="AllowClose" type="bool">true</property>
<property name="Hidden" type="bool">false</property>
<property name="PartOrder" type="int">1</property>
<property name="DisplayHCImage" type="bool">false</property>
<property name="DisplayHCTitle" type="bool">false</property>
<property name="DisplayHCProps" type="bool">false</property>
<property name="DisplayHCDescription" type="bool">false</property>
</properties>
</data>
</webPart>
</webParts>
The web part implementation itself can be any language it wants to, as it’s ‘just code.’ However, since all SharePoint sites are cast into a particular language, the web part implementation should generally follow the language of the particular site.
Deploying web parts to the bin vs the GAC
A frequent question is, where should I deploy my web parts? To the bin directory of a web application, or the global assembly cache?
bin web parts have the benefit that you can use code access security to lock down the set of things the web part can do, providing a defense in depth benefit for web parts. e.g.., if you expect a web part to only render a weather forecast, you can deny it the ability to write to the file system, and the web part will fail if it attempts to do that. Note that by default code access security is very restrictive for web parts, so if your web part actually does anything you WILL need to configure CAS for your web part. It's not optional. Depending on your deployment mechanism, dealing with deploying CAS policies can be quite difficult.
Also, bin web parts are deployed per web application, which means that every web application needs to have the assembly deployed in its local BIN directory. This can make deployment difficult - especially if you are using a technology like Windows Installer to do deployment. This can also be a benefit, as it allows you to isolate the availability of code to a subset of servers.
GAC web parts don’t really benefit from CAS – generally, GAC web parts are always full trust – but they are “easier to deploy” because you only need to drop them in one location, and don’t need to configure CAS policies for them. All web parts and controls shipped by WSS and MOSS are deployed to the GAC.
So, the difference between the two is a difference between ease-of-deployment (GAC) vs. having more security tools (code isolation, code access security) at your disposal.