SharePoint 2010 column default values missing
Default Column Values
SharePoint 2010 has some great document management enhancements. One of these is the ability to set location based metadata defaults. This allows you to specify default metadata for documents based on the document library or folder they are uploaded to (i.e. a document could be automatically tagged with Subject=Legal when uploaded to one folder or Subject=Finance if uploaded to another). This is especially useful in situations where users are bulk adding documents that need to have the same metadata applied.
The Problem
I was showing a developer this feature recently when I noticed that on one particular library the column default settings were not applied. The settings were available and I could set the properties correctly using the default column values page but when we tried to add documents the default metadata was not applied (i.e. items that had default values set in the column default values page showed blank fields in the edit form).
Solution
One reason for this problem is that by default Visual Studio 2010 creates all list definitions under the /Lists/ subfolder within a site (yes even document libraries). After inspecting the default metadata component I found that this is hardcoded to only use top level folders for a web (e.g. /site/DocumentLibrary will work but /sites/Lists/DocumentLibrary won’t). If you just want the fix then make sure you remove the /Lists/ path when creating list instances in Visual Studio, if you want to know why then read on.
Investigation
I knew that the Location-Based Metadata Defaults were applied using an ItemAdded event receiver so I inspected the list using SharePoint Manager 2010 to find out what class it was using. This showed me that the event receiver was using the Microsoft.Office.DocumentManagement.LocationBasedMetadataDefaultsReceiver class in the Microsoft.Office.DocumentManagement assembly. Using .NET Reflector I opened this class to investigate further and found it used the following code:
internal class LocationBasedMetadataDefaultsReceiver : SPItemEventReceiver
{
// Methods
[SharePointPermission(SecurityAction.LinkDemand, ObjectModel=true)]
public override void ItemAdded(SPItemEventProperties properties)
{
if ((properties != null) && (properties.ListItem != null))
{
SPListItem listItem = properties.ListItem;
SPWeb currentWeb = listItem.Web;
string afterUrl = properties.AfterUrl;
MetadataDefaults defaults = new MetadataDefaults(SPUrlUtility.CombineUrl(currentWeb.ServerRelativeUrl, afterUrl.Substring(0, afterUrl.IndexOf('/', 1))), currentWeb);
string url = listItem.Url;
string folderPath = SPUrlUtility.CombineUrl(currentWeb.ServerRelativeUrl, url.Substring(0, url.LastIndexOf('/')));
if (defaults.HasFieldDefaults(folderPath) && defaults.ApplyDefaults(listItem, properties.List.Fields))
{
listItem.SystemUpdate(false);
}
}
}
}
After running some similar code to see what was happening I found the problem was a down to the MetadataDefaults constructor with a fragile method of determining the list URL:
MetadataDefaults(SPUrlUtility.CombineUrl(currentWeb.ServerRelativeUrl, afterUrl.Substring(0, afterUrl.IndexOf(‘/’, 1))), currentWeb);
This expects the list URL to be in the form /site/list. On the list in question this had been set to /site/lists/list so the constructor was called with MetadataDefaults(‘/site/lists’) which caused problems later on when the MetadataDefaults class expected to find a list at that URL.
Updating the URL so it no longer resided in the ‘/lists/’ subfolder fixed the problem and generally I’d recommend creating document libraries at the root to avoid other oddities like this but the ‘/lists/’ subfolder happens to be the default when creating document library list definitions in Visual Studio 2010 so I’m sure this won’t be the only time it catches people out. This can be avoided by using the listItem.ParentList.RootFolder.ServerRelativeUrl property instead of performing string manipulation on the URL so I’m classing this as a bug.
Hopefully either the Visual Studio 2010 tools and/or the event receiver code are updated so this doesn’t catch others out. While it is easy to fix in a development environment I can see this causing problems if people create lists using this method in a production environment and then later try and use this feature. So to sum up make sure you remove that ‘/lists’ prefix when creating document library list instances in Visual Studio 2010!
Update 9 March 2011: I’ve noticed you also run into issues if you create a slide library list instance within the /Lists/ subfolder. When you try to delete a slide library you are taken to a page with a URL similar to http://teams/Lists/_layouts/DeleteMu.aspx?ListId={2A833EA9-9444-49AF-A7DA-32EF76BB90C9}&SelectedIds=1 and you receive a blank page with the message ‘File not found’. Another reason to avoid the /Lists/ folder in the URL when creating document libraries (or subtypes like the slide library).
Awesome. Nice find Ari.
Merill
1 Mar 11 at 10:08 pm
As a side note (and also as for a reference for myself) – if you want to see the raw default metadata stored for a list you can navigate to [list url]/Forms/client_LocationBasedDefaults.html to see the xml that stores the values.
Ari Bakker
16 Jun 11 at 7:39 pm
I am running into something similar to this. I have an event receiver for ListAdded that will create metadata column(s) and then set the default metadata values. The creation of the columns works perfectly, but I get the same error described here when the MetadataDefault class tries to update.
My structure is similar to this:
http://server/sites//Lists/
Have you heard anything from MS about correcting this?
Tom Hill
4 Nov 11 at 4:26 pm
Oops. Formatting killed my example link – let’s try this:
http://server/sites/sitename/Lists/listname
Tom Hill
4 Nov 11 at 4:27 pm
I know this is an old post, but this particular issue seems to be now fixed – ‘LastIndexOf’ is now used instead of ‘IndexOf’:
string folderPath = SPUrlUtility.CombineUrl(web.ServerRelativeUrl, url.Substring(0, url.LastIndexOf(‘/’)));
Jonathan Cardy
13 Mar 14 at 11:53 am