Category Archives: SharePoint Development

SharePoint Delegate Controls Unclouded

Introduction

Over the past few months I have been working on branding the SharePoint portal of one of the largest international companies. This was really interesting especially that this was the first branding experience for me. While I was looking at the OOB master page ( default.master ), I noticed there is a control called “delegate control” in the head element right below the “PlaceHolderAdditionalPageHead”. After googling and investigating, I can say that Delegate Control is one of the most important features of SharePoint 2007 when it comes to branding and customization.

History

Back to 2003, When Microsoft released Microsoft SharePoint portal server 2003, it was cool but what extremely annoyed the developers then is the non-extensibility of the product and the difficulty of customization. Now, MOSS 2007 offers many extension points to alter sites even after they have been provisioned. The introduction of SharePoint features has opened up an entire world to modifying master pages, page layouts and the pages themselves. Further, SharePoint introduced Delegate Controls that allow for more granular control over parts of the page.

Why are they cool and handy ?

On every SharePoint deployment I have ever participated in, it has been requested that the Search Box be modified. In previous SharePoint versions, this involved either unghosting and customization and/or creating a whole new site definition. NOW, Thanks to Delegate Controls, you can take any control and place them on a SharePoint page such that they substitute the existing control at whatever scope you desire and yet require no extra coding or redeployment of the pages themselves. They work hand-in-hand with the newly introduced Features Framework to dynamically load a control at runtime based on a key value and sequence number

Enough Theory, How do they work ?

The default.master file that the global site definition deploys contains some Delegate Controls with the following Id values :

  • AdditionalPageHead
  • GlobalSiteLink0
  • SmallSearchInputBox
  • PublishingConsole

For instance, SmallSearchBox displays a search area and the DelegateControl Definition in default.master is :

<SharePoint:DelegateControl runat=”server” ControlId=” SmallSearchBox”>

All versions of SharePoint contain a feature called ContentLightUp that includes a Control element that specifies a control for the DelegateControl with the SmallSearchArea ControlId value. The element looks like this :

<Control Id=”SmallSearchInputBox” Sequence=”100” ControlSrc=”~/_controltempaltes/searcharea.ascx” />

The enterprise version of MOSS contains a feature named OSearchEnhancedFeature that substitutes the searcharea.ascx user control with SearchBoxEx web control that sends the user to the more advanced search page in MOSS.

<Control Id=”SmallSearchInputBox” Sequence=”50″ ControlClass=”Microsoft.SharePoint.Portal.WebControls.SearchBoxEx” ControlAssembly=”Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral,PublicKeyToken=71e9bce111e9429c”>

When SharePoint selects the control to replace the delegate control, it looks through the list of activated controls and selects the best control and the best control is defined as the one that has the lowest sequence number. Because the control element in OSearchEnhancedFeature has a lower sequence number, the control it defines is loaded instead of the one determined in ContentLightup and this occurs without modifying default.master .

There are other DelegateControls, like AdditionalPageHead, that do not have visual elements but instead provide the ability to insert additional HTML at runtime.

For example, I once created a web control called SearchEngineOptimizer that emited META tags ( Meta Tags are html tags that appear in the head of html pages) for search engine optimization and created a feature to load that web control!

Well, there is a couple of tips and recommendations that I want to highlight :

  • By using a feature scoped at web, you can use different search boxes for different areas in your site collection with no extra code.
  • You can load user or server controls, if you are specifying a user control, use URL attribute, if you want to load a server control use ControlClass and ControlAssembly attributes.
  • By adding AllowMultiple=true in to the delegate control declaration, you can make it load more than one user/server controls. ( for instance AdditionalPageHead delegate control is set to allow multiple controls by default).
  • When designing your page, create delegate controls for functionality that might change over time.
  • Keep tack of the sequence and don’t use too low numbers. You don’t want to have trouble overriding the feature in the future.

Summary

Delegate Controls are important design options for creating solutions that can mixed and matched with other options. The ability to light up functionality for one site and not another can be a very important tool in the SharePoint developer’s toolbox.

User Controls in SharePoint

SharePoint makes extensive use of User Controls, They are located in the 12 hive in Template\ControlTemplates.
Examples : Welcome.ascx , Toolbar.ascx,…
The deafult web.config includes the content of this folder and its subfolders in the SafeControls section.

So any user control you manually create and place it in the 12 hive in Template\ControlTemplates is automatically considered safe by the safe-mode parser.

What are ISAPI Filters ?

An ISAPI filter is a DLL that runs on an IIS server to filter data traveling to and from the server to enhance the functionality provided .
They filter every request until they find one they need to process. Filters can be programmed to examine and modify both incoming and outgoing streams of data. Internally programmed and externally configured priorities determine in which order filters are called.
Filters are implemented as DLL files ( can only be developed using unmanaged C/C++. ) and can be registered on an IIS server on a site level or a global level (i.e., they apply to all sites on an IIS server).

Filters are initialised when the worker process is started and listens to all requests to the site on which it is installed until they fine one they need to process.

Common tasks performed by ISAPI filters include:

  • Changing request data (URLs or headers) sent by the client
  • Controlling which physical file gets mapped to the URL
  • Controlling the user name and password used with anonymous or basic authentication
  • Modifying or analyzing a request after authentication is complete
  • Modifying a response going back to the client
  • Running custom processing on “access denied” responses
  • Running processing when a request is complete
  • Run processing when a connection with the client is closed
  • Performing special logging or traffic analysis.
  • Performing custom authentication.
  • Handling encryption and compression.

Sources : MSDN and Wikipedia

What are ISAPI Extenions?

ISAPI consists of two components: Extensions and Filters. In the last post we briefly discussed the laster. Now I’d like to shed some light on ISAP Extensions.

Most of the modern web sites do more than just deliver static HTML. When a site requires dynamic content, an application is needed to handle the requests, process them and respond.
ISAPI Extensions are true applications that run on IIS. They act as the engine for which the actual server side code is written. Clients can access ISAPI extensions in the same way they access a static HTML page. Certain file extensions can be mapped to be handled by an ISAPI extension ( Just like file associations in Windows , ex. Doc files are associated with WinWord.Exe).

Common ISAPI applications implemented as ISAPI extensions:

  • ASP.dll extension processes traditional ASP Pages
  • aspnet_isapi.dll extension processes ASP.NET Pages.

A Site Collection Is A Boundary

Talking about the difference between a site collection ( SPSite ) and a site ( SPWeb ) , the Site Collection is the unit of authorization for all sites ( SPWebs ) it contains .
I usually see it as a boundary for both security and querying information. In SharePoint we can query information and aggreagate them from different sites ( SPWebs ) but this is limited to the boundaries of a site collection.
In this respect you can think of the query visibility as analogous to aggregating data from two different databases using an SQL Query. In case of Databases, there should be an intermediate step to achieve that and get the correct result set and the same is true for our beloved SharePoint LOL.

Hiding SharePoint Site Templates & Adding new categories!

A colleague asked me about removing some of the templates/site definitions that are available when creating SharePoint sites. Actually It’s so simple.
To hide a template from users :

1) Open the Webtemp.xml file located in the the 12 hive /template/1033/XML folder.
2) Change the Hidden parameter of the template(s) you want to hide.
3) Run IISRESET

Note also that you can create your own categories by editing the DisplayCategory value

Master Pages Tokens

Hi guys, It’s a little post, but I thought it would be useful for beginners to SharePoint branding.
“Master Pages” is an essesntial topic when it comes to SharePoint Branding as they provide consistency by providing a common layout, content, look and feel across the pages that use them.

Note the reference to the token ~masterurl/default.master in the first line in any sharepoint content page.

When you use the attribut MasterPageFile into your page header, you can give the relative url of the master page you want.
There also some token to give you more options :
Dynamic token :
“~masterurl/default.master”>>> This token references a master page from a content page by using the MasterPageFile attribute together with the value of the MasterUrl property. And this resolves by default to /_catalogs/masterpage/default.master but you can change the MasterUrl property using SharePoint designer or using Master Page page under Site Settings via the browser .
“~masterurl/custom.master”>>> This token references a master page from a content page by using the MasterPageFile attribute with the value of the CustomMasterUrl property . Also it resolves to /_catalogs/masterpage/default.master by default.

MSDN Note : If you subsequently need to delete the default.master file, you must set both of those properties to a different value.
Static token :
“~site/x”>>> This token link to the current site-relative path
“~sitecollection/x”>>> This token link to the current site collection-relative path

For example, if your content page is located at http://myPortal/subsite1/subsite2/default.aspx and you use the token “~sitecollection/mypage.master”, your content page would use the master page athttp://myPortal/mypage.master. If you use the token “~site/mypage.master”, the content page would use the master page located at http://myPortal/subsite1/subsite2/mypage.master .

Tip : It’s also possible to control the selection of Master Pages at run time with .NET code using the page’s OnPreInit method or by using an HttpModule. ( will be discussed in later posts ) .

Be Careful When Using properties & SPContext

What is SPContext ?
In a nutshell, SPContext object can be used to get a reference to the site or the web from the current context, It Represents the context of an HTTP request in SharePoint .
For instance :
SPList currentList = SPContext.Current.List;
SPWeb currentSite = SPContext.Current.Web;
SPSite currentSiteCollection = SPContext.Current.Site;
SPWebApplication currentWebApplication = SPContext.Current.Site.WebApplication;
SPListItem item = (SPListItem)SPContext.Current.Item;
SPUser user = SPContext.Current.Web.CurrentUser;

What is “Properties” ?
The properties object holds information about an event. You can use it to get references to SPSite, SPWeb, SPList or SPList Item.
for instance :
SPListItem item = properties.ListItem’

However,
Be VERY careful when using properties parameter or SPContext. You CANNOT use the properties command to create your objects or your code will fail! .
You need to use properties or SPContext to locate the items, then use the items IDs to create the object references. You will never get your code to work the way it is above.
You need to get all of the Guid identifiers BEFORE entering the secure block ( RunWithElevatedPriveleges) or Impersonation, then create all the objects you need WITHIN the secure context

Guid SiteId = SPContext.Current.Site.ID;
Guid WebId = SPContext.Current.Web.ID;
Guid ListId = properties.ListId;
Guid UniqueId = properties.ListItem.UniqueId;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site= new SPSite(SiteId))
{
using (SPWeb web= site.AllWebs[WebId])
{
SPList list= web.Lists[ListId];
SPListItem listItem= list.Items[UniqueId];
// Code..
}
}
});

or to impersonate the system account using SPUserToken ( Recommended )

Guid SiteId = SPContext.Current.Site.ID;
Guid WebId = SPContext.Current.Web.ID;
Guid ListId = properties.ListId;
Guid UniqueId = properties.ListItem.UniqueId;
SPUserToken systemAccountToken = SPContext.Current.Site.SystemAccount.UserToken;
using(SPSite mySite = new SPSite(SiteId, systemAccountToken))
{
using (SPWeb myWeb = mySite.OpenWeb(WebId))
{
SPList list= web.Lists[ListId];
SPListItem listItem= list.Items[UniqueId];
// Code..
}
}

SPUserToken, The Hero !

A few days ago, I wrote event handler code that runs in the security context of the logged in user. SharePoint security model makes it easy to programmatically execute code within the current user context But there were some situations when the code needs to be executed with permissions greater than that of the current user (like instantiating a site collection or enumerating list permissions ).

In such situations, the code needs to be executed with elevated permission level or under the context of user with higher permissions i.e. Impersonation.
As the MSDN documentation says, SPSecurity.RunWithElevatedPrivelege “Executes the specified method with Full Control rights even if the user does not otherwise have Full Control.”
In my experience with Using SPSecurity.RunWithElevatedPrieveleges, there are too much tricks that you should take care of.
For Instance : You must create the new SPSite objects inside the delegate because SPSite objects created outside do not have Full Control even when referenced inside the delegate. Use the using keyword to ensure that the object is disposed in the delegate. The next example shows this. SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(web.Site.ID))
{ // Perform elevated actions here
}
});
The problem is that the SPWeb object from the current context is initialized using the current user’s credentials, so even though we run the code snippet with elevated privileges the actual access to the file is still restricted. To resolve this we have to create a new SPSite/SPWeb object within the elevated code, where we run in the context of the elevated user. Then we can perform the restricted action. Since the SPSite/SPWeb objects are created explicitly we have to also dispose of them.
There’s too much overhead, too much chances of introducing obscure bugs, too much potential abuse when it comes to using SPSecurity.RunWithElevatedPrievelges.

That’s why I’d recommend to use SPUserToken to impersonate the SYSTEM and use elevated privileges.

Fortunately, the SystemAccount SPUser is a property of any SPSite object. So instead of using SPSecurity.RunWithElevatedPrivelege, you can use the following code to perform elevated actions:

SPUserToken systemAccountToken = SPContext.Current.Site.SystemAccount.UserToken;
using(SPSite mySite = new SPSite(SPContext.Current.Site.ID, systemAccountToken))
{
using (SPWeb myWeb = mySite.OpenWeb(SPContext.Current.Web.ID))
{
// Perform elevated actions here
}
}

The Evils of AllWebs !

As I have been working to develop an event handler that will be used to mirror a Document Library, I’ve come across an interesting tid bit that was frustrating at first.

It’s worth mentioning that in MOSS 2007, Event Handlers execute in the context of the current user rather than the process user in SharePoint 2003 .

The event handler contained the following piece of code :
using( SPWeb web = SPContext.Current.Site.AllWebs[guid] )
{
// code
}

When running as an administrator, the event handler worked fine. However, if you switch to a non-administrative user that doesn’t have full control of the site, you’ll get a lovely exception. The problem is that you must have full control of the site to be able to use the AllWebs property.

To solve this, try the following code:

using( SPWeb web = SPContext.Current.Site.OpenWeb(guid) )
{
// code
}

Happy SharePoint Coding 😀