[4/26/2010] Updated with interface changes from beta2 to rtm
In SharePoint 2010 there is a new feature called the Document ID. When that feature is enabled, it will assign an unique ID and a permanent url to the document in a document library. Documents can be found using that Document ID, even if the document is moved to another location within the document library, site, or farm.
The default structure of the DocumentID is: <PrefixString>-<ListId>-<ListItemId>
Example: E2E4NK52YQC4-2-4
That prefix string is created as a unique string for every Site Collection. The first way to customize the DocumentID is to use the Document ID Settings page in Site Settings.
In this page you can change the prefix string:

But if that is not enough customization, there is also an other way: Your own DocumentIDProvider implementation.
Just derive your class from the abstract class Microsoft.Office.DocumentManagement.DocumentIdProvider and implement 1 property and 3 methods,
But before we take a look at the methods we need to implement, let's take a look how Document IDs work.
How does a Document ID work
When a document is added to a document library and the Document ID feature is enabled in that site collection, the event ItemAdded is trapped and the registered Document ID Provider is asked to generate a Document ID. This ID is then assigned to the DocumentID column. Note that the asynchronous event ItemAdded is used and not ItemAdding to be able to access metadata for the Item when assigning Document IDs. This page in the documentation explains more about the different events that are used: Document IDs and the DocID Service.
When you use a view that includes the DocumentID column or when you view the properties of the item, you will notice that the Document IDs are rendered as links to: _layouts/DocIdRedir.aspx
There is also a Document ID webpart to search for documents (The normal search also finds documents with Document IDs). That webpart also uses the DocIdRedir.aspx page.
If you want to add this webpart, it's in the Documents Category and not in the Search Category:

How does DocIdRedir.aspx work?
The DocumentID column is an indexed property of Search. So when your document is indexed it can be found by using the Search API. But the Out-of-the-box DocumentIdProvider does something smarter first.
Remember that the default structure of the DocumentId is: <Prefix>-<ListID>-<ListItemID>. So before asking SharePoint Search to find the document, it will first check the prefix if that is the prefix of the current Site Collection and if it is it can quite easy get the Item based on the ListID and ListItemID. If the item exists and it has the same DocumentID then the users is redirected to this document. If the document can't be found via this optimized way, then the Search API is used. If that also can't find the document then an error is shown.
Example of error message:

That is the behaviour of the Out-of-the-box DocumentIdProvider. Now we have enough information to look on how to custimize the provider.
Custom DocumentIdProvider
The generating of Document IDs can be custimized by creating a class that derives from Microsoft.Office.DocumentManagement.DocumentIdProvider
The definition of DocumentIdProvider:
namespace Microsoft.Office.DocumentManagement
{
public abstract class DocumentIdProvider
{
protected DocumentIdProvider();
public abstract bool DoCustomSearchBeforeDefaultSearch { get; }
public abstract string GenerateDocumentId(SPListItem listItem);
public abstract string[] GetDocumentUrlsById(SPSite site, string documentId);
public abstract string GetSampleDocumentIdText(SPSite site);
}
}
You have to implement the 3 abstract methods and 1 abstract property. But how are they meant to be used?
DoCustomSearchBeforeDefaultSearch
So what does this property do? Remember that the ootb provider first tries to find the document based on the ListId and ListItemId and if that doesn't give a result it will revert to using SharePoint Search. This boolean controls that behaviour. Notice that there is also a GetDocumentUrlsById method in this interface.
If you return true, then you let the DocIdRedir.aspx know that you want it to call the GetDocumentUrlsById first before calling Search. If you let this Property return false, you want to use SharePoint Search first, before using the GetDocumentUrlsById method. Note that it will only tries the 2nd search method when the first search method doesn't return a result!
GenerateDocumentId
This method is needed to generate the DocumentId. The SPListItem is passed as an argument in case you want to generate a Document ID based on the list item metadata. You have to return your DocumentId as a string.
GetDocumentUrlsById
This method is used to return the urls of the document based on a Document ID. This can be used as an alternative when the document isn't indexed yet and therefor the Search way didn't returned a result. Or if you have beter way to retrieve the document in the Site Collection.
If you don't want to return any urls, just return an empty string array.
return new string[0];
If DoCustomSearchBeforeDefaultSearch was true, then returning the empty string array will signal the DocIdRedir.aspx to try it again with the SharePoint Search.
If DoCustomSearchBeforeDefaultSearch was false then the SharePoint Search was called first but didn't gave a result and the GetDocumentUrlsById was called. Returning an empty string array in that case will generate a message that the file could not be found.
An other possible scenario is that you set DoCustomSearchBeforeDefaultSearch to false and rely on the SharePoint Search. And if that can't find your document, you use the GetDocumentUrlsById to return a fixed url to a page that informs the user that the document can't be found (e.g. The document might not be indexed at this time if it was recently added.)
GetSampleDocumentIdText
This method is used to populate the Document ID webpart with an example.

The text E2E4NK52YQC4-1-1 is returned by this method in above example.
Registering the provider?
So now that you have implemented your custom DocumentIdProvider, how do you get it registered to a Site Collection (or unregistered)?
I didn't find any STSADM or PowerShell command for that, but the class Microsoft.Office.DocumentManagement.DocumentId has 2 methods that we can use:
public static void SetDefaultProvider(SPSite site);
public static void SetProvider(SPSite site, DocumentIdProvider iProvider);
The method SetProvider will register your provider to SPSite and removing it is done by calling SetDefaultProvider.
A good way to call these methods is in the events of a Feature event receiver.
Example:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = (SPSite)properties.Feature.Parent;
DocumentId.SetProvider(site, new GuidDocumentIdProvider()));
}
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = (SPSite)properties.Feature.Parent;
DocumentId.SetDefaultProvider(site);
}
Once the custom provider is registered, you will not be allowed to change the prefix in the Document ID Settings page in Site Settings.Which is logical, since you are no longer using the OOTB DocumentIdProvider.
Example source code
I also uploaded an example implementation to the Files section. It includes a SharePoint 2010 project for Visual Studio 2010 (beta2). That project contains the Custom DocumentIdProvider called GuidDocumentIdProvider that uses GUIDs as Document IDs and a feature GuidDocumentIdFeature to enable and disable the GuidDocumentIdProvider.
Code can be found here: Custom DocumentIdProvider Example
When experimenting with this example, make sure you crawl your SharePoint site after adding documents, otherwise the documents can not be found by the DocIdRedir.aspx page.
Posted
12-05-2009 2:49 PM
by
Michel Barneveld