Contact   •   Products   •   Search

Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs

Creating a unique or semi-unique ID in .NET


I have a few applications where I need to create some unique IDs that can't be GUIDs. GUIDs are great if you truly need a globally unique identifier, but they are a bit of overkill when it comes to application that locally unique ids. GUIDS are nice but they are big. If you need to represent them as strings the 38 characters it uses with punctuation is a bit excessive. There's nothing that I hate more than browser querystrings that have 3 GUID IDs embedded in them <g>…

 

The most common places I need these simple ids are for temporary identifiers. For example when I send a request to my Credit Card Processor there's an ID that correlates my invoice with the transaction at the provider. The providers has some odd rules about the invoice numbers so if somebody needs to resubmit the order it won't go through – hence I need to create a new ID. Anyway, a GUID isn't what I'd want here.

 

Invoices too. I tend to give invoices an ID that is not just a number but yet reasonably easy for a user to work with. Handing a 34 digit numeric string isn't going to fly with customers.

 

So… in light of this, what's a good way to create an ID in .NET? In Fox I used to use SYS(2015) for this, which works pretty reliably except in very volume multi-threaded environments. Unfortunately I'm not sure what it uses to generate this id.

 

Invoice.Invno = DateTime.Now.ToString().GetHashCode().ToString("x");

 

which produces something like this:

 

369bf2e0

 

Now, I've never had a problem with this but reading over the documentation of GetHashCode() it indicates that GetHashCode() doesn't generate unique hashcodes. If the value isn't guaranteed to be unique how can it be used as a hash of a value? That's a bit confusing…

 

In regards to strings then it seems to contradict the above:

 

For example, the implementation of GetHashCode provided by the String class returns unique hash codes for unique string values.

 

So, does that mean that any one string representation can be expressed only by a unique hash? I can't imagine this being true.

 

So if I do:

 

Guid.NewGuid().ToString().GetHashCode().ToString("x");

 

469cf3e1

 

Somehow I don't think that this string representation at least is unique… 38 characters represented as 8? Ok 32 bits, but still it's 8 digits and characters limited to hex values.

 

Here's an interesting link that talks about some of the GetHashCode inconsistencies with the documentation:

 

http://www.interact-sw.co.uk/iangblog/2004/06/21/gethashcode

 

Even with that in mind it's not really clear to me if generating a string with the values above would be safe or not.

 

So what other options are there to generate a reasonably unique ID?  Maybe a better way is:

 

DateTime.Now.Ticks.ToString("x")

 

which generates:

 

8c8113da982d75a

 

and which is getting a bit long at 15 characters. Ticks is a 64 bit so it makes sense that the string is a bit longer.

 

Hmm... for the invoice example I mentioned earlier I suppose using a hex representation of the PK would work. Or even a hashcode of the PK. Nope - Integer values persisted aren't properly random (10 turns into a and GetHashCode() for integers just returns the value).

 

What else? How about using part of a GUID string? Is there any part of a GUID that can be dissected and be acceptable as a non-network safe ID?  Doesn't look like it – if you generate new GUIDs every single character changes in the string representation.

 

 

 

Make Donation


Feedback for this Post

 
# re: Creating a unique or semi-unique ID in .NET
by Hagay March 09, 2006 @ 3:05am
GetHashCode job is to reutrn as unique as possible identifier.

in order to improve efficiency of hashtable structure the keys should be unique in best case.

.net's hashtable can work when you assign duplicate hashcodes, but its less efficent
(for each same hashcodes it builds an array/linked list and then perform Equals method on the values of that array to determine the correct one to return)

so in worst case, hashtable preformance reduced to linear search performance with quite a memory overhead :)
# re: Creating a unique or semi-unique ID in .NET
by Martin Möbius March 09, 2006 @ 3:26am
For the hashCode thing an older Java article. I expect that the most is true for .net too.

http://www-128.ibm.com/developerworks/java/library/j-jtp05273.html

For the UID problem. Why not an easy counter?
Just make it threadsafe with synchronized, or use the InterLock class.
Would be at least unique for the lifetime of the application.
You can persist the counter value in a database or a file before the application ends.
Or init the counter with DateTime.Now and the hash of the IP during application start. Would be at least unique for the machine. A restart of a crashed application hopfully takes longer than the tick for DateTime.Now.

Put the stuff into a singleton class.
# re: Creating a unique or semi-unique ID in .NET
by Frank Camp March 09, 2006 @ 4:21am
Hi Rick,

I've uploaded the routines to the UT a long time ago, to convert sys(2015) values to date/time and back.

The url is: http://www.universalthread.com/wconnect/wc.dll?2,54,33,9704
# re: Creating a unique or semi-unique ID in .NET
by Craig Boyd March 09, 2006 @ 5:27am
The message digest (hash) of a GUID is not guaranteed to be unique - all hash functions have theoretical collisions given that the message digest is a compressed representation of the original. However the chance of those collisions needs to be taken into consideration. With 8 hex digits you're looking at what? 16^8 permutations? That's 4,294,967,296 unique message digests. So, given a unique GUID string, would this ID be guaranteed to be unique? No, but pretty good for what you're proposing to use them for (this of course assumes that there aren't any major flaws with the hash algorithm or implementation that MS is using to derive the message digest). For the ID to be guaranteed unique you'd need to generate the ID and then check it against the current existing IDs to make sure it wasn't a duplicate. Or, you could increase your chances by hashing the GUID string using a higher level hash function such as SHA1 (160 bit). But then you're increasing the length of the ID again, so that's not really a solution. I think you've hit upon about the best solution there is with GetHashCode() of a GUID given what you intend to use it for.
# re: Creating a unique or semi-unique ID in .NET
by Jeff Atwood March 09, 2006 @ 6:49am
It is possible to compress GUIDs (128-bit numbers) down into more compact ASCII representations:

http://www.codinghorror.com/blog/archives/000409.html

That's 128 bits of data in 20 printable ASCII bytes. Not too shabby!

If you use smaller numbers, you have the pigeonhole principle to contend with. But the odds of it being an actual problem are so small.
# re: Creating a unique or semi-unique ID in .NET
by Bertrand Le Roy March 09, 2006 @ 9:25am
Yup, the mistake here is to use hexadecimal.
# re: Creating a unique or semi-unique ID in .NET
by Steve March 09, 2006 @ 9:46am
Craig, very good response.
# re: Creating a unique or semi-unique ID in .NET
by Rick Strahl March 09, 2006 @ 1:21pm
Jeff - it figures you'd been down this path before <g>... Great link!

Hex encoding the GUID is not that different from just stripping out the dashes. Interesting to compare these two values:

Guid g = Guid.NewGuid();
string strGuid1 = g.ToString();

StringBuilder sb = new StringBuilder();

// *** Hex definition
byte[] byt = g.ToByteArray();
foreach (Byte b in byt)
{
sb.AppendFormat("{0:x2}", b);
}
string strGuid2 = sb.ToString();

Bertrand - one advantage of using Hex is reasonably easy to read even with a mix of numbers and digits.

So given all this talk about Guids - how about the DateTime string or the TickCount? That string will be fairly short compared to Guid and unique and should provide a more reliable hash value assuming you can deal with the possible time conflict (down to the millisecond).
# re: Creating a unique or semi-unique ID in .NET
by Havagan March 10, 2006 @ 1:56am
I know zero about crypto (so ignore me if this makes no sense) but wouldn't a function similiar to one which generates random passwords using the System.Security.Cryptography.RNGCryptoServiceProvider class create a reasonably random value if you limit the allowed characters to only alpha-numeric?

Public Function GetRandomPassword() As String
Dim maxSize as Integer = 20
Dim minSize as Integer = 15
Dim chars() as Char = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray
Dim size As Integer = maxSize
Dim data(1) as Byte
Dim crypto As new RNGCryptoServiceProvider
crypto.GetNonZeroBytes(data)
size = data(data(0) Mod (maxSize - minSize)) + minSize
ReDim data(size)
crypto.GetNonZeroBytes(data)
Dim result As New StringBuilder(size)
For Each b As Byte in data
result.Append(chars(b Mod (chars.Length - 1)))
Next
Return result.ToString
End Function


# re: Creating a unique or semi-unique ID in .NET
by joe March 10, 2006 @ 11:08am
Rick - be careful using GetHashCode.
The implementation changed from .Net 1.1 to 2.0. So the same string value returns different values depending on the framework. This is why there is a warning to not store the hascode value in a database and expect to be able to re-generate it across .Net versions.
# re: Creating a unique or semi-unique ID in .NET
by Anon March 13, 2006 @ 8:02am
How about using a simple Base36 structure? http://www.codeproject.com/csharp/base36.asp
# DotNetSlackers: Creating a unique or semi-unique ID in .NET
by DotNetSlackers Latest ASP.NET News January 08, 2007 @ 5:14pm
# re: Creating a unique or semi-unique ID in .NET
by Darrell February 22, 2007 @ 10:26am
Rick,

Did you ever decide on a solution to this issue?

I wonder if System.IO.Path.GetRandomFileName() is comparable to sys(2015).
# A Continuous Learner's Weblog: March 2006
by A Continuous Learner's Weblog May 23, 2007 @ 2:00pm
# Lautz of .NET - Not so Random, Pseudo-Daily Links of Interest #1
by Lautz of .NET June 11, 2007 @ 2:49am
# re: Creating a unique or semi-unique ID in .NET
by Jorge Ojeda Belmar December 27, 2007 @ 5:42am
IMHO I think that it's easer to use an identity value from DataBase.
What do you think?
# re: Creating a unique or semi-unique ID in .NET
by Oscar March 24, 2008 @ 8:31am
Hi. Has anyone tried the Base36 method above? Results?
# re: Creating a unique or semi-unique ID in .NET
by ALexander Nel August 06, 2008 @ 7:32am
Hi all, try this:

Dim oGUID As New Guid()
Dim g As Guid = Nothing
g = Guid.NewGuid()
Dim sGUID As String = g.ToString()
sGUID = sGUID.Replace("-", "")
sGUID = sGUID.Substring(7, 25)

Tested it on 1000001 GUID's, with no doubles found. In this case I only had 25 characters to use as a Unique Identifier.

Remember to import: System.GUID

Cheers
# re: Creating a unique or semi-unique ID in .NET
by Max Pool March 17, 2011 @ 5:13pm
I am facing this exact issue only faced with only 13 character limit. Although, still completely possible to collide, I used this pattern to minimize the collisions even more:

DateTime.Now.Year.ToString() + Guid.NewGuid().ToString().GetHashCode().ToString("x");

Perfect? No....but at least my probability of 1:16^8 colliding starts over every year....
 


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2014