Demystifying Document ID's

Demystifying Document ID's header image

Ever since SharePoint 2010 the Document ID feature has been around. In theory a pretty awesome feature for applying ‘unique’ identifiers to your documents. So whenever building solutions that somehow have to do with Document Management you will end up looking to it, and in some cases implementing it. Now besides the fact that is bound to a site collection it’s a pretty decent feature. The fact that it is bound to a site collection introduces a small disadvantage since that means an ‘unique’ identifier is only unique for that site collection, and not for your farm or web application. But knowing that you could work around that by setting prefixes yourself, and thus making sure everything is as unique as it should be. However doing ‘stuff’ from code with the document id providers seems a bit confusing at start, so in this blog an introduction in the workings of the Document ID as it is implement in SharePoint 2013.

The Document ID process consists of two separate parts, there is a Site Collection feature called Document ID Service that you can enable and that will allow you to configure the document id prefix, and there are two timerjobs that will do some work. Those two timerjobs will only run once a day, so it might take up to a day before you will see the document id’s as you expect them. If you think of doing the stuff manually there are some pitfalls, so below you will find the order that you should keep in mind when working with document id’s

Feature: Document ID Service

Activating the feature does a few things, it will assign a Document ID as we would do in code ourselfs:

DocumentId.EnableAssignment(site, null, fActivate, fActivate, false, false);

The only thing noticable is that it will not set a prefix, and thus ‘generate’ one for us, however this method will do some more for us. Before actually activating it will determine the size of our site, and based on that it will activate the Document ID Assignment, or it will create a work item to do so:

if (DocIdHelpers.IsSiteTooBig(site))
{
    DocIdEnableWorkitem.ScheduleWorkitem(site, prefix, fEnable,
        fScheduleAssignment, fOverwriteExistingIds,
        fDocsetCtUpdateOnly);
}
else
{
    DocIdEnableWorkItemJobDefinition.EnableAssignment(site,
        prefix, fEnable, fScheduleAssignment,
        fOverwriteExistingIds, fDocsetCtUpdateOnly);
}

The site is defined as to big when one of the following requirements is met:

  • The site has a subweb (if it has more then 1 web, including the rootweb)
  • The site has more then 40 lists
  • The site has more then 20 document libraries

That means that if we enable the feature, or assign an new prefix through code it will always check the sizing of the site before enabling Document ID’s. If a work item gets created both timerjobs should run before you will see the prefix as you expected. However there is another pitfall, the scheduling of the work item is done by the following code:

site.AddWorkItem(Guid.Empty,
    DateTime.Now.AddMinutes(30.0).ToUniversalTime(),
    DocIdEnableWorkItemJobDefinition.DocIdEnableWIType,
    site.RootWeb.ID, site.ID, 1, false, Guid.Empty, Guid.Empty,
    site.RootWeb.CurrentUser.ID, null, strTextPayload,
    Guid.Empty);

The thing to notice there is that it will create a new work item as expected, but it does so with a scheduled date that is 30 minutes from the moment you activate the feature. That means that you can run the timerjobs as much as you like, but it will take 30 minutes before your site will be processed.

Timerjobs

There are two timerjobs that will need to be executed in the right order to have the prefix working on your farm. The first on is the Document ID enable/disable job, this will process the work items on all sites, and make sure that the prefix is pushed to all subwebs on the site collection. And then there is the Document ID assignment job, this job will push the required settings to all lists on the webs, and make sure that documents that are created after the feature was turned on are updated with the correct ID (and prefix).

If you would run the Document ID assignment job before running the enable/disable job it will not process your web properly, and you will not see the expected Document ID’s.

Eventreceivers

When running the Document ID assignment job one of the steps that will done in the web (and its lists) will be to update all the Content Types with the event receivers that are needed to update documents with an Document ID. When those event receivers are not present you will see entries in the ULS that it will try to process the item, but nothing else happens and the item itself will be not be stamped with a Document ID. So if you are running into issues where your documents are not provided with a Document ID in certain lists make sure that the following event receivers are present:

Document ID eventreceivers

You could use a tool like SharePoint Manager to quickly determine if they are.

Now in our case we had some issues that some lists did miss those event receivers, and as it turned out the following occurred. If you have an STP file of your list that you use to create a list instance from, and you do not activate the Document ID feature before you create your list instances the event receivers are missing. However if you enable the feature, and then create the list instances they get provided with the correct event receivers and everything works

Then finally if you would like to set a custom prefix from code (for instance if the site is created), you will end up using code that looks like this:

using (SPSite newSite = new SPSite(site.ID))
{
    LoggingService.LogVerbose("DocumentID", String.Format("Reloaded site object: '{0}'", newSite.ID));
    LoggingService.LogVerbose("DocumentID", String.Format("DocumentId.IsAssignmentEnabled: '{0}'", DocumentId.IsAssignmentEnabled(newSite)));
    LoggingService.LogVerbose("DocumentID", String.Format("DocumentId.IsFeatureEnabled: '{0}'", DocumentId.IsFeatureEnabled(newSite)));

    // Make sure the feature is activated
    if (newSite.Features[new Guid("b50e3104-6812-424f-a011-cc90e6327318")] == null || !DocumentId.IsFeatureEnabled(newSite))
    {
        LoggingService.LogVerbose("DocumentID", "Activating DocumentID feature");
        site.Features.Add(new Guid("b50e3104-6812-424f-a011-cc90e6327318"));
    }

    DocumentId.SetDefaultProvider(newSite);
    DocumentId.EnableAssignment(newSite, id.ToString("RWS00000"), true, true, true, false);
}

And to round things up a quick tip, you can check almost the complete process of things happening by enabling verbose logging on the product Document Management Server.

Loading comments…