Using SPGridView with Microsoft Office SharePoint Server 2007

Some developers new to SharePoint might not understand why they would want to use a SPGridView control over a ASP.NET GridView control for rendering lists of data.   I think the #1 reason for me is  that the SPGridView control makes your custom web parts look just like the out of the box SharePoint list views. It also has some very nice sorting and filtering functionality built in when used with an ObjectDataSource.

In a previous post I explained how you could create an ObjectDataSource from a DataTable.  In this post I will show how to utilize the ObjectDataSource with the SPGridView to allow for easy sorting and filtering of data.

To get started we need to implement the DataTableWrapper class shown below.    We will also need to define an instance of the DataTableWrapper class and a DataTable object that will be used for our actual source of data for the grid.

public class DataTableWrapper
    private DataTable _dt = new DataTable();
    public DataTableWrapper(DataTable dt)
            _dt = dt;

     public DataTable GetTable()
             return _dt;


    DataTable sourceDataTable;
    DataTableWrapper myDataTable;

Now that we have our supporting wrapper class and a couple of objects defined it is now time to assign an actual DataTable instance to the sourceDataTable object.   Do this using whatever method is appropriate for your situation.   The goal is to have a DataTable object called sourceDataTable filled with the records you wish to display within the SPGridView control.

The code below creates an instance of the DataTableWrapper class based upon the sourceDataTable. This is done so we can retrieve the qualified type name of our DataTableWrapper object which is required by the ObjectDataSource.

An ObjectDataSource is then created which will be used as the actual source of data for the SPGridView.   It is very important to make sure you add the ObjectDataSource to your controls collection.  If you skip that step you will get a fairly cryptic error message which really doesn’t help identify the root cause of the issue.

 //Create instance of wrapper to grab type.
            myDataTable = new DataTableWrapper(sourceDataTable);
            Type t = myDataTable.GetType();

 //Create ObjectDataSource
            ObjectDataSource ds = new ObjectDataSource();
            ds.ID = "myDataSource";
            ds.TypeName = t.AssemblyQualifiedName;
            ds.SelectMethod = "GetTable";
            ds.ObjectCreating += new ObjectDataSourceObjectEventHandler(ds_ObjectCreating);


To use a custom object (such as our DataTableWrapper) with the ObjectDataSource you need to handle the ObjectCreating event as shown below.   This creates an instance of the DataTableWrapper based on our sourceDataTable.   The ObjectDataSource will then call the GetTable method from our wrapper class whenever it needs to get all of the records from our sourceDataTable.

void ds_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
            myDataTable = new DataTableWrapper(sourceDataTable);
            e.ObjectInstance = myDataTable;

We are now ready to create our SPGridView control. One thing to know about the SPGridView is that you must set AutoGenerateColumns property to false and then manually create the columns.  If you do not do this you will receive an error.   If you wish to enable sorting for columns then set the AllowSorting property to true.

 //Create Grid
            SPGridView fileListingGrid = new SPGridView();
            fileListingGrid.AutoGenerateColumns = false;
            fileListingGrid.AllowSorting = true

Add a BoundField object as a column to the SPGridView for each column you wish to display.  If you want to control the formatting of the data or add controls to the SPGridView you will need to create template columns.  Using template columns with the SPGridView is the same as using them with the ASP.NET GridView control.   For an example see:  Dynamic Template Columns in the ASP.NET 2.0 GridView Control.

BoundField myField = new BoundField();
myField.HeaderText = "The Title";
myField.DataField = "Title";
myField.SortExpression = "Title";

I think the properties are self-explanatory for the BoundField object so I won’t go into too much detail here.  I do want to point out that in order for automatic sorting you must set the SortExpression property.   This should, in most instances, be the same value as the DataField property.

Once all of the columns have been defined for the SPGridView control you can set the DataSourceID property to the ID of the ObjectDataSource.   In our case we set the SPGridView’s DataSourceID property to myDataSource.

You will notice that prior to calling the DataBind method on our SPGridView object we are adding it to our controls collection.  If you try to call the DataBind method prior to adding the control to the controls collection you will receive an error.

fileListingGrid.DataSourceID = "myDataSource";

You should now have a working SPGridView control that implements basic sorting.

To enable filtering you need to set a few other properties on the SPGridView control prior to calling the DataBind method.  Below you will find an example of the properties that need to be set in order to enable filtering.   I recommend the blog post Filtering with SPGridView for in depth details on how to configure filtering.

fileListingGrid.AllowFiltering = true;
fileListingGrid.FilterDataFields = "Title";
fileListingGrid.FilteredDataSourcePropertyName = "FilterExpression";
fileListingGrid.FilteredDataSourcePropertyFormat = "{1} like '{0}'";

As you can see using an ObjectDataSource with a SPGridView control allows you to get sorting, filtering with a consistent SharePoint look and feel with very little effort.

The magic undocumented SharePoint 2007 command

Looking for a quick way to ruin your evening?  One quick simple command can quickly turn that nice looking enterprise portal into a big pile of nothingness.  I guess on the brighter side of things it provides a nice opportunity to test out that disaster recovery plan you created.

So what is this command?  It is the undocumented SharePoint 2007 stsadm –o uninstall command.   Once quick hit of the enter key and you can kiss all of your hard work goodbye.    Ok, ok… so it doesn’t delete everything but it does make a nice mess.

The interesting thing here is that stsadm does not list this as a valid command but if you type it and hit enter it will remove SharePoint from the default virtual server at port 80.  This happens without any confirmation prompt to protect you from accidentally trashing your environment.  The good news is that your content databases are not damaged during this.

It looks like this command is left over from SharePoint 2003 and is listed in SPS2003 reference materials on TechNet.

Having this command still available in SharePoint 2007 is extremely dangerous since developers and SharePoint admins will frequently use the installfeature and uninstallfeature commands.  If a person accidentally hits the enter key after typing stsadm –o uninstall instead of stsadm –o uninstallfeature they will watch their whole SharePoint portal rendered useless in a matter of seconds.

Big lesson here is to be VERY careful with the uninstallfeature command and to make sure you always have a recent full farm backup available incase you make a mistake.

Sometimes Single Sign-On

SSO aka Single Sign-On seems to be one of the most requested features from business users.   It is very common to hear end users complaining about having to remember different passwords or having to re-enter their login credentials over and over just to use internal systems.    But is SSO what they really want?

The problem with single sign-on is the same as it’s benefit.   A user just has to log into their desktop and then they have full access to any other system within the organization without having to provide login credentials again.   This means that if a user walks away from their PC and leaves it unlocked anyone could sit down and have access to not only files and information on the local PC but also on any of the organizations systems. 

So what can be done to protect sensitive data?  One option is to have a policy that all computers must be locked when a person leaves their desk.    This is a good practice even when SSO is not implemented in an organization.    However, this relies on the individual to remember to lock their system.   How many times have you seen someone just walk away from their PC or laptop without locking it?  I see this on a daily basis.

Another option is to enable the “on resume, display logon screen” in the screen saver settings and then set a 1 minute inactivity timer.   This would automatically lock any system left alone for more than one minute, but still a lot could happen within that first minute of a computer being left alone.

Once users realize the security risks of SSO they start thinking that maybe they really want SSSO aka “sometimes single sign-on”.   They want to be prompted for login credentials when accessing human resources and payroll information.    They want to be prompted for login credentials when accessing other systems with similar sensitive information.  For non-critical systems or those not holding sensitive data the users do want SSO.

SSO can be very time consuming, complicated and expensive to implement.  I recommend that you think very carefully about your own organization and get lots of input from the end users, line of business owners, and IT personnel before jumping into an SSO project.   You just might find out that you don’t really need or want SSO.

SharePoint User Profile Access Issues

Today I will feature a problem recently encountered with updating and reading user profile information when connected to SharePoint as an anonymous user.

The Task
…create a custom login page for forms based authentication that validates specific user profile information prior to allowing the user to log into SharePoint.  In this instance a user would enter in their usename and password and then click on the login button.    The button’s click event will launch a method that validates user profile information for the specified username prior to completing the actual log in process.   This is needed to make sure a user has read and agreed to the site terms of service prior to be given any access to the system.   A simple user profile field that is not editable directly by the user holds the flag that indicates if the user has agreed to the terms of service.   If the user has previously agreed to the terms then the log in process completes.  If the user has not previously agree to the terms then the terms are displayed and the user has a chance to agree and login or disagree and leave the site.

The Problem
I need to read and update user profile information even though the user has yet to log into SharePoint through forms authentication.   The initial thought was to use SPSecurity.RunWithElevatedPriviliges to provide the elevated permissions needed to read and write to the profile store.    Elevated permissions are required because anonymous users do not have any permissions on the profile store.

During testing of this solution I still continued to receive access denied errors when the exists method of the UserProfileManager object was executed.  This made no sense since the application pool account had full permissions to make modification to the user profile store.   (Note: when using RunWithElevatedPriviliges under a forms authenticated site the actual account used is the application pool account).

The Cause
With help from Lutz Roeder’s .NET Reflector utility I was able to peak into the actual SharePoint assemblies and view what was going on when I was calling the exists method on the UserProfileManager object.   I eventually tracked down the exact piece of code that was causing the access denied error.   It was in a static method called GetCurrentUserName in the UserProfileGlobal class.

Since this class is protected under Microsoft copyright I will not be reproducing the actual code but I will explain at a high level what the GetCurrentUserName method does and why it caused the access denied errors.

The GetCurrentUserName class inspects the HttpContext.Current property and if it is not null it uses it to determine the current user and validates that the user can be authenticated and then returns the username.    If the HttpContext.Current property is null then the current WindowsIdentity is used to determine the current user and then returns that username.

So back to our problem… the access denied error.    When using RunWithElevatedPriviliges impersonation takes place and the WindowsIdentity object now returns the SharePoint system account (which in our case is the application pool account).   RunWithElevatedPriviliges does not modify the HttpContext, so in our case since our user is not authenticated the HttpContext.Current.User property is set to an empty string.  This means that when the GetCurrentUserName method from the UserProfileGlobal class executes it sees the the HttpContext.Current property is not null and then attempts to validate the username which is an empty string.   This causes the method to return an access denied error.

The Workaround
Because our HttpContext.Current object is not null we keep falling into the part of the GetCurrentUserName method that tries to validate the username what happens to be an empty string because we do not have any user logged in yet.   What we really want is the HttpContext object to be null so that the method instead uses the SharePoint system account which does have full permissions over the user profile store.    If we just set HttpContext.Current = null we would cause the login page to no longer work.   This is because ASP.NET needs the HttpContext in order to properly process and render a web page.

To prevent the ASP.NET page from no longer working it is important to store the value of the current context in a variable prior to setting the current context to null so that way it can be restored when done reading or writing from the user profile store.   Below is an example.


HttpContext myContext = HttpContext.Current;
HttpContext.Current = null;

…do profile read / writes here …

HttpContext.Current = myContext;

Remember that the above code is run within a RunWithElevatedPriviliges code block.   It is also important to make sure you do not try to use any objects or methods that need access to the HttpContext object between the time you set the current context to null and when you restore it to the original value.

So far this work around appears to be performing very well in a development environment.   If you do use this please be aware that future changes to the SharePoint API through service packs, hotfixes or other updates may cause code relying on this work around to no longer function as intended.   In other words, use at your own risk! 

Multi-Page Meeting Workspace – Missing Tabs

Today I had a very interesting situation arise related to SharePoint 2007 mult-page meeting workspaces.    Below is a summary of the problem and how it was resolved.


On a meeting workspace the page tabs are missing and menu items are missing from the site actions menu.


  1. Open up the meeting workspace site in SharePoint designer.
  2. Navigate to the _Catalogs/masterpage folder.
  3. Right click on the default.master file and select Set as Default Master Page.
  4. Right click on the MWSDefault.master file and select Set as Custom Master Page.

More Details:

It turned out the problem was caused when the user went into site settings, selected master page under the look and feel heading and then without making any changes clicked on the OK button.  This caused the custom master page to be set to default.master instead of the mwsdefault.master page required by the meeting workspace. 

This mistake is very easy to make since the mwsdefault.master page is not listed as an option when you are in the site settings.  Since SharePoint is unable to find the mwsdefault.master option in the drop down selection of master pages it automatically defaults to the default.master page.  

To avoid this issue in the future it is recommended that designers are trained to use the cancel button instead of the OK button when leaving a settings page in which they made no modifications.   It is also recommended that the master page link never be used in the site settings section for meeting workspace sites.

SharePoint 2007 Wiki Library Issue

Today I was asked to look into a problem that was occurring in a Microsoft Office SharePoint Server 2007 wiki library.   Below I have detailed the specific issue and the steps to resolve it. ?

Newly created wiki pages cannot be edited.  After creating a new wiki page and then returning to edit it the user is presented with a small document properties form instead of the wiki page editor.   Older wiki pages can be edited and appear to work as intended.

The wiki page when created was assigned the wrong content type (most likely document).   The underlying cause as to how this happened is currently unknown.

To fix the issue all existing pages that were created with the document type must be changed to the wiki page content type.   Also the wiki library itself needs to be modified to remove the document content type.

Warning:  The steps below used to fix the issue require directly modifying SharePoint properties using a 3rd party tool.   Make sure you have a full backup of your SharePoint environment before attempting these steps.   Accidentally changing the wrong property within SharePoint Manager 2007 can cause major damage to your SharePoint environment.   I am not responsible for any problems, damages or losses caused by following these instructions.   Proceed at your own risk.

Here are the steps to fix the issue:
1.  Download and install the SharePoint Manager 2007 (SPM) on the SharePoint server.   Run the program.

2.  Navigate to the wiki library using the SPM tree view.   Expand the wiki node and then under it expand the content types node.   You will most likely see 3 content types:  Documents, Wiki Page, and Folder.   If you see this then the following steps can help you resolve the issue;  continue on with step #3.   If you do not see this then the following steps may not resolve your issue.

3. Click on the wiki node and in the right property panel locate the property ContentTypesEnabled.  It will be set to false.  Change that to true and then click on the save button.

4. Open up a web browser and navigate to your wiki page.   Change the default view to include the field ContentType.  After you complete this step you should see the problem pages listed as a content type of “document” instead of wiki page.  ?

5.  Edit the properties of each page that has a content type of document.  Change the content type to wiki page.

6.  Navigate to the site settings of the wiki library.   You should now see a section listing out the content types.   Choose the document content type and then delete it.   If you did not change the content types of the existing pages you may receive an error message.  In that case return to step #5.

7.  Return to the SPM, right click on the wiki library and select refresh.   After a couple minutes SPM will reload all of the properties.

8.  Make sure the wiki library node is selected in SPM and then change the ContentTypesEnabled property in the right panel back to false.   Click the save button.

Once this has been completed all existing wiki pages and all newly created pages should work correctly.

Visual Studio Web Projects vs Web Sites

Visual Studio 2003 which supported the Microsoft .NET Framework 1.0 and 1.1 provided a method of creating web applications called Web Application Projects.   When Microsoft released Visual Studio 2005 it only supported the creation of web sites; web application projects were no longer an option.   Microsoft then released an add-on to bring back web application projects (in a new form) after numerous complaints from users about difficulties migrating from Visual Studio 2003 web projects to Visual Studio 2005 web sites.  Initially the support for web projects were scheduled to end concurrently with the end of life date of Visual Studio 2005.   Microsoft has elected to keep web projects around with Visual Studio 2008 so the debate between using web projects or web sites continues.

So what is the best practice for the creation of new web applications; use web projects or web sites?   The short answer is it depends.  Each option presents a different way of writing, managing and compiling the code but the end product is still a .NET web application that can be deployed on any ASP.NET compatible web server.

Before we dive in too deep there is once concept that needs mentioning.  Both web sites and web projects in Visual Studio 2005/2008 utilize a new concept in .NET 2.0 called partial classes.   Partial classes allow the developer to split a single .NET class across multiple code files.   This is very different from Visual Studio 2003 where all of the code for a class was managed in a single file.

Below is an overview of each option.  Hopefully this will provide you with enough information to allow you to make an educated decision on which one will work best for you.

Web Application Projects
Web Projects are created by selecting the file menu and then choosing project and then under your language of choice in the new projects window go to the web folder and select ASP.NET Web Application.   With web application projects there is a .proj file that maintains a list of all files, references and project settings used in that project.

This project type allow developers to maintain separation between the presentation and logic of a web page by using an .aspx page and two partial class files.  In this situation the .aspx page contains HTML and .NET markup for creating the visual elements and controls.   A partial class file with the extension of designer.cs or designer.vb is used to hold the control declarations and a .cs or .vb partial class is used for code related to events.  It is important to understand that Visual Studio manages the .designer.cs files and that developers should never manually modify them.

When a web application project is built the code files are compiled into a single assembly file and placed in the web’s BIN directory.   It is important to understand that at no time is the aspx files compiled when using a web application project.  Mismatched control names between the .aspx and designer code file will not be identified during the build process.  Only during application testing will these types of errors surface.   The odds of getting a mismatch between a control name in the .aspx and the declaration in the designer code file is slim if you do not manually change the designer file.

Deploying a web application project is as simple as using xcopy to move the complete application to the production environment.   Since all of the code-behind files (.cs or .vb) is compiled into the assembly it is only necessary to copy the .ASPX and .DLL files.  It is also possible to use the Visual Studio publish feature to make copying the needed files to the final location simple.

One benefit that web application projects have over the web site type is that developers can utilize the pre-build and post-build events built into Visual Studio.   Since a web site doesn’t have a project file it is not possible to set up these events within Visual Studio.   Another benefit is the ability to specify the default namespace used by the application.

Web Sites
Web sites which were introduced in Visual Studio 2005 can be created by selecting the file menu and then choosing new and then web site.   You can create new web sites on the file system, local IIS server or other locations.   If you choose to use the file system, Visual Studio will use a built in light weight web server for testing and debugging your application.   It is important to understand that there is not a project file for web sites.   This means that all files in your web site folders are included in the solution.

An aspx page in a web site is a partial class that correlates with a .cs or .vb (aka code-beside) file that contains the rest of the code for the class. The .aspx file contains HTML and .NET markup that defines the visual elements and controls on the page.  The .cs or .vb code-beside files contains the event handlers for the controls.   When a build occurs for a web site both the aspx and code-beside file are compiled.   This is very different from a web application project in which only the code files are compiled.  Having both the .aspx and code-beside files compiled help the developer identify certain types of errors during the build process and prior to actual testing.

Deploying a web site is as simple as using xcopy to move all of the files including the aspx and code-beside files to the IIS server.   The web server will automatically compile the aspx and code-beside files into separate assembly files upon first access.

In some cases you may not want any of your code easily visible on your server.   In that situation you can use the Visual Studio publish option and remove the check box from the allow this precompiled site to be updatable. This will cause Visual Studio to create an assembly with all of the web site code (including the controls declared in the aspx files).  This leaves a single assembly and .aspx placeholder files which are pretty much empty.   This in essence makes it more difficult (but not impossible) to directly view or update the code for the web site.

If you deploy your web site using the xcopy method it is possible to make quick fixes or updates to your web site just by copying the updated files (not the whole application) to the IIS server.   In most cases this can be done without requiring any down time or restarting of the IIS server.    If you are replacing a partial class on the IIS server that is referenced by other web site classes you may experience problems unless you restart the web server (ex.  IISRESET), so this isn’t always a “no down time” type of update.

Web sites was Microsoft’s intended direction for developing web applications starting with Visual Studio 2005.   Microsoft released an update to Visual Studio 2005 to add back web application projects due to upgrade/migration issues from Visual Studio 2003 web application projects to Visual Studio 2005 web sites.   Both types allows developers to create web applications and deploy them in a similar manner

So should you use web sites or web application projects?  Only your architect or lead developer can make that decision. The important thing is to keep consistent with your development practices.

Vista on an old HP Laptop

OK… don’t ask why I would do this but I decided to install Vista Ultimate on an older (3+ year old) HP laptop.   An HP Pavilion zx5180us to be exact.   The install actually went very smooth.   Once I plugged it into a wired network connection Windows update managed to find all of my devices including my wireless card and installed in perfectly.   Even the video driver was updated (no Aero however… the laptop just isn’t equiped for that).    The only problem I ran into was the lack of audio.    The driver Windows update kept sending down (Realtek AC’97) would fail every time.    🙁
After spending a few hours messing with this I finally figured it out.   I used the hardware IDs to track down a set of drivers from ATI called the ATI Chipset / Southbridge drivers.   So far the only place I have found them for download is at   It sucks because you either have to pay for the driver download or click through a series of ads.    Anyways, once I receieved the file I unzipped it onto my hard drive.   I tried to run the setup program but just ended up getting error messages and being told I need to reboot.     So I did just that;  rebooted the laptop.   Of course on boot up Vista wanted to help and said hey… I found new hardware… let me install the AC’97 driver for you.   Of course that fails as exepected.   I opened up device manager, selected the AC’97 device and then selected update driver.
I selected to browse my computer for driver software.  I followed that up with the selection of let me pick from a list of device drivers on my computer.   This then allowed me to choose have disk.    I navigated to the recently downloaded and unzipped ATI files (the folder was C:ChipsetATI SouthbridgeAudio) and selected the only INF file shown.    A warning was shown about the driver not being signed…  since I am desperate I went ahead full steam and instructed the system to install the drivers anyways.   A few minutes later and I had audio!
WOOT!   Who said you can’t teach and old laptop new tricks?
Now everything seems to be workin,,g well… last step to reinstall office and get my email working again.

ObjectDataSource from a DataTable

I recently ran into a situation where I needed an ObjectDataSource in order to use the sort and filter capabilities of the SharePoint SPGridView control, however, my data was already in a DataTable.

I found out that I could use the ObjectCreating event of the ObjectDataSource in order to set the control to an existing data object, such as a DataTable.    I was pretty excited to see that I would be able to take the existing DataTable and expose it as an ObjectDataSource.    That excitement was short lived as I continued to have problems getting it to work with the SPDataView control.  ?

The issue is that the ObjectDataSource was configured to call the Select method of the DataTable whenever the SPGridView control requested data.   This caused the ObjectDataSource to return a DataRow array which the SPGridView did not understand.   I needed the ObjectDataSource to return the data as a complete DataTable and not DataRow array.

The solution that I arrived at is to create a very simple wrapper class around my DataTable object that returned the original DataTable when a method is called on the wrapper class.   Once implemented I had a perfect rendering SPGridView with both filtering and sorting enabled. ?

Below is an example of the wrapper class:

public class DataTableWrapper
private DataTable _dt = new DataTable();

public DataTableWrapper(DataTable dt)
_dt = dt;

public DataTable GetTable()
return _dt;

Here is an example of connecting this up to the ObjectDataSource:

ObjectDataSource ds = new ObjectDataSource();
ds.ID = “myDataSource”;
ds.TypeName=”[…strong name of your DataTableWrapper class here]”;
ds.ObjectCreating += new ObjectDataSourceObjectEventHandler(ds_ObjectCreating);

And here is the ObjectDataSource ObjectCreating event handler:

void ds_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
myDataTable  = new DataTableWrapper(sourceDataTable);
e.ObjectInstance = myDataTable;

Things to note about the above samples:

  • The original data source sourceDataTable was defined with class scope.  This allows the ds_ObjectCreating method to access it.
  • myDataTable was defined with class scope.
  • The TypeName of the ObjectDataSource must be the full strong type name for the DataTableWrapper object.

Maybe there is a simpler way of doing this.   I would love feedback if you have any suggestions.

STSADM import / export cont.

A few more lessons learned while using the STSADM export and import commands:


1.    Alerts will not follow the site’s lists and documents during the export process.

2.    Email enabled lists can be an issue when importing if the destination server is not properly configured for incoming email.

3.    Any task or issues list imported that emails a user when they are assigned a task will no longer send emails.  You need to disable and then re-enable the functionality in the lists settings.

We are also using the Microsoft IT Site Delete capture feature found at   It appears that this will not protect imported sites unless you disable and then re-enable this feature on the web.   I have not had time to dig into this specific topic but I do have firsthand knowledge of an imported site not being caught by the IT Site Delete capture feature when the site was deleted.   

I am also guessing that references to custom event handlers will also not be imported, but I have not had a chance to verify this.

Overall the stsadm export and import commands can be very useful to move sites around as long as you remain aware of the limitations.

Technology Blog