How to Create a Custom Document-ID Provider with SharePoint 2013

How to create a Custom Document-ID provider with SharePoint 2013

In May 2014 I’m going to talk about professional Document Management with SharePoint 2013 at the ESPC in Barcelona and this blog post was intended to be a published right after my session. However, when the ESPC team asked me for a blog post I couldn’t resist to publish this post prior to talking about it.

When using SharePoint 2013 as a platform for document management in an enterprise there is often the requirement to assign a unique number to documents – think of case numbers or reference numbers.

Microsoft introduced the Document-ID service in SharePoint 2010 and of course the Document-ID service is also available in SharePoint 2013. To use the standard Document-ID provider that ships with SharePoint you simply need to activate the following site collection feature:

O1

Because the Document-ID service is activated as a site collection feature you can be sure that the created Document-IDs are unique within the current site collection.

To ensure that Document-IDs are unique within a web application (or any other scope) there are two ways that you can go:

1. You can browse to the site collection settings and open the Document-ID settings. Here you can add a prefix to the Document-IDs that are generated by the standard Document-ID provider. You need to provide a unique prefix for every site collection.

O2

2. If you need to ensure that Document-IDs are really unique and if Document-IDs need to be in a special format or notation as a requirement by an enterprise (as a part of enterprise governance rules) you can develop a custom Document-ID provider. A custom Document-ID provider is created by code and replaces the standard Document-ID provider at the same scope.

To create a custom Document-ID provider you need to setup a new project in Visual Studio and create a new class that is derived from the class DocumentIDProvider.This class is part of the namespace Microsoft.Office.DocumentManagement. In my example I’m using Visual Studio 2012 (installed in my SP2013 development VM) and the SharePoint Software Factory (SPSF) framework to assist me in setting up and maintaining the project – as I do in most of my SharePoint development projects.

As you might expect that’s not all the work that needs to be done. After you have created a new class you need to overwrite (implement) some abstract methods.

The first method that needs to be implemented is GenerateDocumentID(). This method is called when a new Document-ID needs to be created – for example when a new document has been added to a library. As the only parameter the current item is handed over to this method.

In my example I add some code to create a simple unique number. In an enterprise’s environment a more sophisticated implementation is required – especially if the Document-IDs need to follow certain governance rules.

This is how my code looks now:

using System.IO;

using Microsoft.Office.DocumentManagement;

using Microsoft.SharePoint;

namespace CustomDocumentIDProvider.Components

{

    class CustomDocumentIDProvider : DocumentIdProvider

    {

        public override string GenerateDocumentId(SPListItem listItem)

        {

            string retParam = “SPDocID-“;

            string path = Path.GetRandomFileName();

            path = path.Replace(“.”, “”);         

            retParam += path.Substring(0, 8).ToUpper(); 

            return retParam;

        }

    }

}

Next you need to implementGetSampleDocumentIdText(). This method is called when the default value of a new Document-ID needs to be displayed. This happens when the WebPart Find by Document-IDis rendered. The method is called with the current site as the only parameter – just to give you access to the current site and its properties.

In my example I just return a preconfigured static string.

This is how my code looks now:

using System.IO;

using Microsoft.Office.DocumentManagement;

using Microsoft.SharePoint;

namespace CustomDocumentIDProvider.Components

{

    class CustomDocumentIDProvider : DocumentIdProvider

    {

        public override string GenerateDocumentId(SPListItem listItem)

        {

            string retParam = “SPDocID-“;

            string path = Path.GetRandomFileName();

            path = path.Replace(“.”, “”);         

            retParam += path.Substring(0, 8).ToUpper(); 

            return retParam;

        }

        public override string GetSampleDocumentIdText(SPSite site)

        {

            return “SPDocID-HT7G4SP7”;

        }

    }

}

Next you need to implement a property. This property is called DoCustomSearchBeforeDefaultSearch. Quite a long name for a property but very meaningful. This property is used to determine how documents should be retrieved by their Document-ID. If this property is set tofalse,documents are retrieved by SharePoint Search first before a custom method of the provider is called. If it is set totruea custom method of the provider is called first before SharePoint Search is invoked.

I would like to provide a closer look on this property, because it is helpful in another scenario. A custom Document-ID provider needs to implement a method that retrieves documents by a given Document-ID (I’m going to implement this method next). There are basically two ways how documents can be retrieved by their Document-ID:

  • Calling the provider’s method GetDocumentUrlsById()
  •  Invoking the SharePoint Search index.

Although retrieving a document by its Document-ID might be a good job for the powerful SharePoint Search, invoking a method of a custom Document-ID provider has a distinct advantage – it’s faster in most cases. That’s because the provider’s method does not need to wait for the next incremental crawl to finish. It can retrieve a document by a given id just after it gets called.

There is another scenario in which this method gets invoked. What happens if a document with a Document-ID is moved from one site collection to another site collection – if it is moved from the scope of one Document-ID provider to the scope of another Document-ID provider? The document can be found by its Document-ID using the standard Document-ID provider in the target site collection (after it has been moved here) only, if there had been at least an incremental crawl that has just updated the index. In this case the document is not found by the methodGetDocumentUrlsById()  of the standard Document-ID provider. Please refer to my blog post for further details: http://sharepointcommunity.de/blogs/owirkus/archive/2013/03/26/sharepoint-moving-a-document-with-a-document-id-to-another-site-collection.aspx

This is how my code looks now:

using System.IO;

using Microsoft.Office.DocumentManagement;

using Microsoft.SharePoint;

namespace CustomDocumentIDProvider.Components

{

    class CustomDocumentIDProvider : DocumentIdProvider

    {

        public override string GenerateDocumentId(SPListItem listItem)

        {

            string retParam = “SPDocID-“;

            string path = Path.GetRandomFileName();

            path = path.Replace(“.”, “”);         

            retParam += path.Substring(0, 8).ToUpper(); 

            return retParam;

        }

        public override string GetSampleDocumentIdText(SPSite site)

        {

            return “SPDocID-HT7G4SP7”;

        }

        public override bool DoCustomSearchBeforeDefaultSearch

        {

            get { return false; }

        }

    }

}

Now it’s time to implement GetDocumentUrlsById(). This method is called with two parameters: the current site and the Document-ID to look for. It needs to return an array of strings with valid URLs.

For this example I will implement this method returning an empty array. You can find a sample implementation for this method on MSDN. Please follow this link for further information:  http://msdn.microsoft.com/en-us/library/microsoft.office.documentmanagement.documentidprovider(office.14).aspx

This is how my code looks now:

using System.IO;

using Microsoft.Office.DocumentManagement;

using Microsoft.SharePoint;

namespace CustomDocumentIDProvider.Components

{

    class CustomDocumentIDProvider : DocumentIdProvider

    {

        public override string GenerateDocumentId(SPListItem listItem)

        {

            string retParam = “SPDocID-“;

            string path = Path.GetRandomFileName();

            path = path.Replace(“.”, “”);         

            retParam += path.Substring(0, 8).ToUpper(); 

            return retParam;

        }

        public override string GetSampleDocumentIdText(SPSite site)

        {

            return “SPDocID-HT7G4SP7”;

        }

        public override bool DoCustomSearchBeforeDefaultSearch

        {

            get { return false; }

        }

        public override string[] GetDocumentUrlsById(SPSite site, string documentId)

        {

            return new string[] { };

        }

    }

}

This is a basic implementation of a custom Document-ID provider and it is now ready to get tested. There’s only one question left: how can this custom Document-ID provider be used to replace the standard Document-ID provider of SharePoint 2013?

A quick solution would be to use a SharePoint feature. The namespace Microsoft.Office.DocumentManagement provides a suitable method (SetProvider()) to replace the standard Document-ID provider with a custom one.

FeatureActivated:

DocumentId.SetProvider(properties.Feature.Parent as SPSite, new CustomDocumentIDProvider());

FeatureDeactivated:

DocumentId.SetDefaultProvider(properties.Feature.Parent as SPSite);

Now it’s time to test the custom Document-ID provider. I first activate my feature and the standard Document-ID feature.

O3

After that I have a look on the Document-ID settings:

05

The custom Document-ID provider has been activated successfully – this is what the red message confirms.

Now I add a new document to a document library to prove that custom Document-IDs are created as expected. For this test I used a simple textfile:

06

As you can see by looking at the prefix: this Document-ID has been created by the custom Document-ID provider.

Let’s have a look on the Document-ID WebPart. This WebPart should be prefilled with the string that the methodGetSampleDocumentIdText() returns.

07

If you have a look back on the code you’ll notice that this is exactly the (static) string that the method returned.

Let’s use this WebPart for the next test too. I take the Document-ID from the textfile that I have just added to the library and paste it to the WebPart. I also place a breakpoint on the methodGetDocumentUrlsById()- just to prove that this is called now.

O8

After I copied the Document-ID to the WebPart I click on the bluesearcharrow. The breakpoint gets hit (remember that the method is returning an empty array), I press F5 to continue and this is what SharePoint 2013 is displaying now:

O9

This is expected because the property DoCustomSearchBeforeDefaultSearch is set to false and so the SharePoint Search is called first. There had been no crawl right now and so the document can’t be found in the Search index. That’s why the custom method is called afterwards. The custom method returned an empty array (stating that it did not find any matching document). Both search methods did not find any matching document and that’s why SharePoint displayed this message.

Now I force SharePoint 2013 to do an incremental crawl. After the incremental crawl has been completed I repeat the WebPart search. As before the SharePoint Search is called first but now the document could be found in the index. That’s why the provider’s method is not called afterwards.

SharePoint shows that a document with the given ID has been found by retrieving it from the SharePoint Search index that just had been updated by the latest incremental crawl. Because I added a simple textfile to the library before, the contents of this textfile is shown in the browser directly.

O10

This is how a basic custom Document-ID provider can be created by code. Not much work to do – the most important part is to implement an algorithm that can retrieve documents by their Document-ID without invoking the SharePoint Search index.

If you would like to learn more about how to setup a professional Document-Management system with SharePoint 2013, I would like to invite you to listen to my session at the European SharePoint Conference 2014 in Barcelona (May 8th,  TH10, 11:45 am). It’s called Moving Mountains with SharePoint.

List of references:

Thanks to Tobias Zimmergren for providing basic information on how to create a custom provider with SharePoint 2010. [ http://zimmergren.net/technical/sp-2010-sharepoint-server-2010-creating-a-custom-document-id-provider]

MSDN: Document IDs and the DocID Service in SharePoint Server 2010 (ECM) [ http://msdn.microsoft.com/en-us/library/ee559302(office.14).aspx]

 

Oliver WirkusOliver Wirkus is Senior Consultant at the IT consulting company Bridging IT GmbH in Mannheim/Germany. As a SharePoint expert and software architect he has long standing experience in conducting international projects. Customers from different industries like power suppliers, pharmaceutical and financial companies rely on his knowledge as a SharePoint expert. Oliver Wirkus has published several professional articles, is a renowned speaker at conferences and maintains the well known SharePoint blog (http://sharepointcommunity.de/blogs/owirkus).

European SharePoint Conference 2015 takes places in Stockholm Sweeden from 9-12 November 2015. View Programme>>

Share this on...

Rate this Post:

Share: