Click to Rate and Give Feedback
MSDN
MSDN Library
Web Development
Visual How Tos
 Generating Unique IDs in Windows Sh...

  Switch on low bandwidth view
Community Content
In this section
Statistics Annotations (0)
Generating Unique IDs in Windows SharePoint Services 3.0

Summary: Learn to create a unique identifier in Windows SharePoint Services 3.0 for all items contained within a site.

Visual How To

Applies to: Windows SharePoint Services 3.0

Microsoft Corporation

March 2008

Overview

In many scenarios, it is useful to have a system-generated unique identifier for all items contained within a site. For example, you may wish to create a unique identifier for all records submitted to the Records Center. Regardless of which library that the record is stored, each record contained within the site has a unique identifier. SharePoint generates an ID for each item in a list, but these ID's are repeated in each list or library and are not unique across the site. Internally SharePoint creates a unique GUID for each item, but it is not exposed to the end user, and even if it were, GUID's are not very user-friendly.

Implementation of our unique ID includes a list for maintaining the value, and an event handler for retrieving and setting the value.

Code It

In this example we use a custom list named "Counter" containing one list item. The list item contains a value in the "Title" field which is used as the unique identifier. Using a SharePoint list automatically provides us with semaphore/locking behavior when retrieving and incrementing the value from the item in the Counter list. This is useful for handling race conditions which occur if multiple threads are using and incrementing the value at the same time.

Accessing and incrementing the unique identifier value is fairly straight-forward. You obtain reference to the list and item containing the identifier value, retrieve and increment the value, then update the item with the incremented value. The code is contained within a method named GetUniqueId and is called from the ItemAdding event handler when a document is added to a library. However, if two documents are added simultaneously, a race condition for the value occurs.

To handle this, the code is placed in a try-catch block. An exception is thrown if the value is dirty i.e. it was updated by another user between the time it was retrieved and updated. If the exception occurs, another attempt is made to retrieve and increment the value. In our example, the retry occurs five times before exiting.

C#
       private static int GetUniqueId(SPWeb web)
        {
            int returnValue = -1;
            int retryCounter = 0;
            int uniqueId = -1;

        ReTry:
            try
            {
                // Get the list and list item
                SPList list = web.Lists["Counter"];
                SPListItem item = list.Items[0];

                // Get the value for the unique id
                uniqueId = int.Parse(item["Title"].ToString());
                
                // Increment and update the value
                item["Title"] = uniqueId + 1;
                item.Update();
                
                // Set the value to return
                returnValue = uniqueId;
            }
            catch (Exception ex)
            {
                // Handle the exception by retrying 5 times
                retryCounter += 1;
                if (retryCounter <= 5)
                {
                    System.Threading.Thread.Sleep(2500);
                    goto ReTry;
                }
                else
                {
                    // Write the exception to the log
                }
            }
            return returnValue;
        }
Visual Basic
        Private Shared Function GetUniqueId(ByVal web As SPWeb) As Integer
            Dim returnValue As Integer = -1
            Dim reTryCounter As Integer = 0
            Dim uniqueId As Integer = -1

ReTry:
            Try
                ' Get the list and list item
                Dim list As SPList = web.Lists("Counter")
                Dim item As SPListItem = list.Items(0)

                ' Get the value for the unique id
                uniqueId = Integer.Parse(item("Title").ToString())

                ' Increment and update the value
                item("Title") = uniqueId + 1
                item.Update()

                ' Set the value to return
                returnValue = uniqueId
            Catch ex As Exception
                ' Handle the exception by retrying 5 times
                reTryCounter += 1
                If reTryCounter <= 5 Then
                    System.Threading.Thread.Sleep(2500)
                    GoTo ReTry
                Else
                    ' Write exception to the log
                End If
            End Try
            Return returnValue
     End Function

Once the value is obtained, it needs to be set on the item that is calling the event handler. In this example, all processing occurs in the synchronous ItemAdding event. After disabling event firing for the event handler, we obtain an SPWeb object and call our GetUniqueId method. It should be noted that, in this example, because we must get the SPWeb object we are adding an extra database round trip for every item added to the repository. In general this is not an ideal situation. The returned value is added to the AfterProperties collection as a name/value pair using the name of the field for the identifier. SharePoint will then automatically set the value when base.ItemAdding is called. Finally, event firing is re-enabled and base .ItemAdding is called.

C#
        public override void ItemAdding(SPItemEventProperties properties)
        {
            base.DisableEventFiring();
            try
            {
                using (SPWeb web = properties.OpenWeb())
                {
                    // Set the unique id value on the item
                    properties.AfterProperties["MyUniqueId"] = GetUniqueId(web);
                }
            }
            catch (Exception ex)
            { }
            finally
            {   base.EnableEventFiring();   }
            base.ItemAdding(properties);
        }
Visual Basic
        Public Overrides Sub ItemAdding(ByVal properties As SPItemEventProperties)
            MyBase.DisableEventFiring()
            Try
                Using web As SPWeb = properties.OpenWeb()
                    ' Set the unique id value on the item
                    properties. AfterProperties("MyUniqueId ") = GetUniqueId(web)
                End Using
            Finally
                MyBase.EnableEventFiring()
            End Try
            MyBase.ItemAdding(properties)
     End Sub
Read It

Our example uses a text field to hold the value. Other field types may be more appropriate based on the type of value you use. To ensure that the value is not arbitrarily modified by users, you should give consideration to security on the Counter list. The Counter list can also be hidden so it does not clutter navigation. Additionally, you can update the value and put the logic to retrieve into a separate class or in a location that controls access to the identifier value.

You can associate the event handler for retrieving and setting the identifier value with specific content types, such as Item or Document, to ensure that the value is generated for any item or document you add to the site. Also, the field used to hold and display the unique value should be read-only and sealed to prevent users from deleting it.

You can use a feature to deploy this functionality. When the feature is activated, you can use a callout code to provision the "Counter" list and ensure it is populated with a single item containing the starting value. You can associate the event handler for accessing and incrementing the counter value with a specific content type or registered on one or more libraries.

See It Video splash screen

Watch the Video

Video Length: 00:06:39

File Size: 4.4 MB WMV

Explore It
Tags What's this?: id (x) Add a tag
Community Content   What is Community Content?
Add new content RSS  Annotations
Link to video does not work...      Galactic Jello ... kadanous   |   Edit   |   Show History
Also, is there a code download link available?
Locking behaviour      Alex Angas   |   Edit   |   Show History
Can this please be explained further as I'm not convinced. Surely there is a chance that code can run between when the data is retrieved:

     uniqueId = int.Parse(item["Title"].ToString());

and when Update is called?

     item.Update();

I would have thought you would need check in/check out enabled on the list to prevent locking.
Tags What's this?: Add a tag
Flag as ContentBug
Video is working now      WSS Editor   |   Edit   |   Show History
Sorry for any issues you may have experienced. The video is working now. Please let us know if you continue to have problems viewing this video. Thanks!
Tags What's this?: Add a tag
Flag as ContentBug
Second on the Locking...      seschu01   |   Edit   |   Show History

I have to wonder the same as the former poster....how do you ensure the same ID is not generated twice, or more without some locking mechanism?

// Get the value for the unique id
uniqueId = int.Parse(item["Title"].ToString());
// Increment and update the value
item["Title"] = uniqueId + 1;
item.Update();

I can definately see the issue where two users could generate two documents and winde up with the same ID thus causing some problems.


Tags What's this?: Add a tag
Flag as ContentBug
Processing
© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Page view tracker