Word XP (2002) issue with a SharePoint 2007 custom document library column

I recently came across a situation related to Word XP and a SharePoint document library that contains custom columns.

The configuration:  The document library contains several custom columns;  most of them being just single line text fields.   There was, however, a few choice columns that were configured as dropdowns.

The issue:  A user checks out a document for editing with Word XP, makes modifications and checks it back in.  The metadata in the choice columns are reset to an empty value instead of holding onto their original values.

The Fix:  This really doesn’t seem to address “why” the issue occurred but once the choice columns were changed from dropdowns to radio buttons the problem disappeared and the the columns retained their proper values.

I would like to hear from anyone who might have additional insight into why this occurs.

Clouds & Collaboration Event

Sogeti will be presenting a dinner seminar titled Clouds & Collaboration in Royal Oak, Michigan on February 18th from 7pm – 9pm.

This event is targeted to CIOs, VPs and Directors of upper mid-size to enterprise companies that are interested in learning more about how to use collaboration and cloud computing to reduce costs, improve productivity and just survive in these tough economic times.

Topics covered during the event will include:

  • The latest business and technology trends.
  • Collaboration as essential for success in business
  • How collaboration and cloud computing enforces each other
  • Cloud computing and IT strategy
  • Software as a service / software plus services
  • Prerequisites for improving collaboration

Those who attend the event will receive a free dinner and can register to receive a complimentary copy of our upcoming book on this topic.

Erik van Ommeren from the US branch of the Sogeti International Research Institute for New Technology will be presenting this exciting topic.    Erik is an author and public speaker on topics such as innovation, collaboration, service oriented architecture, crowdsourcing and new media.

If you are a CIO, VP or Director of an upper mid-size to enterprise company in Michigan and would be interested in attending this free event, please send an email to michael.hacker@us.sogeti.com with your name, title, contact information and name of your company.     We have limited number of spaces available so we cannot guarantee all requests will be accepted.   

For more information on Sogeti visit our website:  http://www.us.sogeti.com

For more information on Sogeti’s research institute visit: http://www.us.sogeti.com/researchinsight/index.htm

Sogeti is one of the world’s leading providers of IT consulting services. Our mission is simple—we are dedicated to helping you build sustainable business solutions by leveraging technology, tools and proven processes to maximize your profits and results.

Founded in 1967,we bring over 40 years of strong IT expertise to help you meet your business needs. And as a member of the Capgemini Group,one of the world’s largest consulting services companies, we are able to provide you with the most extensive, reliable and efficient solutions.

Manage Checked Out Files

In Microsoft Office SharePoint Server 2007 there is an option called Manage Checked Out Files in the settings page of a document library.   This title is a bit misleading because that is not exactly what that option allows you to do.

If you choose the manage checked out files option you may notice that the list is empty even though you have documents checked out.   A small bit of text above the list explains the reason:  “Use this page to manage files which have no checked in version”.     This means that if you have versioning turned on and have at least one version of the document checked in the document will not show up in the list even if it is checked out. 

If you want to see all documents in a library that are checked out you can create a custom view with a filter to show only documents where the field “Checked Out To” is not empty.

How To Change the Name of a SharePoint 2007 Content Database

Recently I wanted to rename a few SharePoint content databases so that their names better reflected the sites and content that they held.  Below are the steps I took to accomplish this task.

Warning:  You are doing this at your own risk.  You should try this on a test server prior to attempting in your production environment.   Make sure you have a backup of your environment before proceeding.

  • Log into SharePoint Central Administration and go to the application management tab.
  • Select the content databases option under SharePoint Application Management heading.
  • Select the web application from the drop down list that is related to the content database.
  • Click on the name of the database you wish to rename.
  • From the Manage Content Database Settings page place a check in the remove content database box.   Note:  This will not delete your database, it only disconnects it from SharePoint.  Click ok to commit the changes.
  • Connect to the SQL Server that hosts the SharePoint databases.
  • To force all connections to drop I right click on the database and choose take offline.  This may take several minutes to complete.  
  • Once the database is offline, right click on it and choose to bring the database back online.
  • After the database is back online you can right click and choose rename.   Change the database to the new name.
  • Return back to the manage content database page in SharePoint Central administration.   Click on the add a content database button.
  • Fill in the database server name and the new database name o the add content database page.   Complete the rest of the fields according to your environment needs and then click ok.

Windows Live Mesh

Windows Live Mesh is a technical preview peer to peer product for keeping files in synch between multiple devices.     Live Mesh also provides an online desktop that allows you to store up to 5GB of data.  This means you can have your desktop or laptop computer sync files to the online desktop, which gives you access to those files anywhere that you have a web browser and internet access.

One of the features that can be very useful is remote desktop.   This can easily replace costly programs such as GoToMyPC for accessing your work computer from home,  or vice versa.   This remote desktop feature appears to work very well through firewalls and the simple Live Mesh tray icon makes it simple to quickly connect to any PC in your “Mesh” network.

If your friends join Live Mesh you can use it’s peer to peer sync capabilities to automatically keep folders on your computer in sync with folders on your friend’s computers;  all secure.   Remember to respect copyright laws.  :-,,)

I personally have found that in my line of work the remote desktop feature can be very valuable in situations where my clients do not have VPN but I need to have remote access to a desktop PC on their network.    The sync to online desktop feature is also nice so that I always have a 2nd copy of important files just in case my main system has a hard drive failure.

I personally find live Mesh a very cool and useful application.

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);
            this.Controls.Add(ds);

 

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";
fileListingGrid.Columns.Add(myField);

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";
this.Controls.Add(fileListingGrid);
fileListingGrid.DataBind();

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.

Results
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.

Problem:

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

Solution:

  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.

Technology Blog