Is it so wrong to seed your GUID?

I don’t know how wrong it is to seed your GUID.  But I did it just for fun and here it is http://wildwires.com/Products/GUID.aspx

I got tired of looking at impersonal GUIDs and I wanted something familiar to look at.  I thought I wonder what if I high jacked a few of those characters for my self.  So I grabbed the first 16, there are 32 in all.  The first 16 I can put in just about anything I want.  The last 16 is the number of seconds since my birth.  So if someone has the first 16 characters and me and at the same exact second in there life as me creates a guid,  well then I guess we’ll have a duplicate.

On the upside, I can get an understanding of what it is I’m looking at and hopefully I’ll be able to do my work faster.  I was making a custom field type, a few site columns, a content type, and a list.  Lots of GUIDs to look at and a lot of double checking.

This morning I blurted out, in turrets style, “Is it possible to have a family of GUIDs? That way maybe you have a chance of recognizing them.” and Jim Wilcox @poliTechnosis picked right up on what I was asking about and shared that facebook prefaces theres with facebooc.  He quickly wrote this code http://politechnosis.kataire.com/2012/06/custom-guids.html 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CustomGuidTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Guid customGuid = GenerateCustomGuid();
            Console.WriteLine(customGuid.ToString("B"));
            Console.ReadKey();
        }

        static Guid GenerateCustomGuid()
        {
            Guid result;
 
            //0xFACEB00C
            //backwards, but required this to achieve desired result.
            byte[] custom = new byte[] { 0x0C, 0xB0, 0xCE, 0xFA  }; 
            byte[] random = Guid.NewGuid().ToByteArray();
            byte[] final = new byte[16];
            for (int idx = 0; idx <16; idx++)
            {
                switch (idx)
                {
                    case 0:
                    case 1:
                    case 2:
                    case 3:
                        final[idx] = custom[idx];
                        break;
                    default:
                        final[idx] = random[idx];
                        break;
                }
            }
            result = new Guid(final);
            return result;
        }
    }
}

I added too it and came up with:

 

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page 
{
    static OrderedDictionary dictionary = new OrderedDictionary();

    protected void Page_Load(object sender, EventArgs e)
    {
        
        //the opportunity here is to allow the users to set their favorite aliases
        if (dictionary.Count == 0)
        {
            dictionary.Add("0", "0");
            dictionary.Add("1", "1");
            dictionary.Add("2", "2");
            dictionary.Add("3", "3");
            dictionary.Add("4", "4");
            dictionary.Add("5", "5");
            dictionary.Add("6", "6");
            dictionary.Add("7", "7");
            dictionary.Add("8", "8");
            dictionary.Add("9", "9");
            dictionary.Add("a", "A");
            dictionary.Add("b", "B");
            dictionary.Add("c", "C");
            dictionary.Add("d", "D");
            dictionary.Add("e", "E");
            dictionary.Add("f", "F");
            dictionary.Add("g", "6");
            dictionary.Add("h", "4");
            dictionary.Add("i", "1");
            dictionary.Add("j", "9");
            dictionary.Add("k", "7");
            dictionary.Add("l", "1");
            dictionary.Add("m", "3");
            dictionary.Add("n", "2");
            dictionary.Add("o", "0");
            dictionary.Add("p", "7");
            dictionary.Add("q", "9");
            dictionary.Add("r", "2");
            dictionary.Add("s", "5");
            dictionary.Add("t", "7");
            dictionary.Add("u", "4");
            dictionary.Add("v", "7");
            dictionary.Add("w", "7");
            dictionary.Add("x", "7");
            dictionary.Add("y", "4");
            dictionary.Add("z", "2");
        }
    }
    protected void Button1_Click(object sender, EventArgs ea)
    {
        Byte[] use = getTimeInSeconds();
        DisplayGuid.Text = GenerateCustomGuid(use).ToString();
    }

    private static Byte[] getTimeInSeconds()
    {
        TimeSpan span = DateTime.Now.ToUniversalTime().Subtract(new DateTime(1970, 4, 9, 10, 32, 0));
        double seconds = span.TotalSeconds;
        Byte[] byt = BitConverter.GetBytes(seconds);
        Byte[] use = new Byte[8];
        for (int it = 0; it < 7; it++)
        {
            use[it] = byt[7 - it];
        }
        return use;
    }

    private string getCharacter(string text, Guid guid, int idx)
    {
        string tempValue = "";
        object o = dictionary[text.ToLower()];

        if(o != null){
            tempValue = o.ToString();
        }
        
        if (string.IsNullOrEmpty(tempValue))
        {

            tempValue = guid.ToString().Substring(idx, 1);
            if (string.IsNullOrEmpty(tempValue) || tempValue == "-" || tempValue == "{" || tempValue =="}")
            {
                //random works terribly bad
                Random random = new Random();
                int randomNumber = random.Next(dictionary.Count - 1);
                tempValue = dictionary[randomNumber].ToString();
            }
        }

        return tempValue;

    }

    private Guid GenerateCustomGuid(byte[] use)
    {
        Guid result;
        Guid randomGuid = Guid.NewGuid();
        
        string part1 = TextBox1.Text.PadRight(8, '*');
        string part2 = TextBox2.Text.PadRight(4, '*');
        string part3 = TextBox3.Text.PadRight(4, '*');
        string sum = "".PadRight(16,'*');
        if (part1 + part2 + part3 == sum)
            return randomGuid;

        byte[] random = Guid.NewGuid().ToByteArray();
        byte[] final = new byte[16];
        for (int idx = 0; idx < 16; idx++)
        {
            switch (idx)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                    final[idx] = Convert.ToByte(Int32.Parse(getCharacter(part1.Substring(6 - idx * 2, 1), randomGuid, idx) + getCharacter(part1.Substring(7 - idx * 2, 1), randomGuid, idx+1), System.Globalization.NumberStyles.HexNumber)); 
                    break;
                case 4:
                case 5:
                    final[idx] = Convert.ToByte(Int32.Parse(getCharacter(part2.Substring(10 - idx * 2, 1), randomGuid, idx) + getCharacter(part2.Substring(11 - idx * 2, 1), randomGuid, idx+1), System.Globalization.NumberStyles.HexNumber));
                    break;
                case 6:
                case 7:
                    final[idx] = Convert.ToByte(Int32.Parse(getCharacter(part3.Substring(14 - idx * 2, 1), randomGuid, idx) + getCharacter(part3.Substring(15 - idx * 2, 1), randomGuid, idx+1), System.Globalization.NumberStyles.HexNumber));
                    break;
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                case 14:
                case 15:
                    final[idx] = use[idx-8];
                    break;
                default:
                    final[idx] = random[idx];
                    break;
            }
        }
        result = new Guid(final);
        return result;
    }
}

}

I’ve change my birth day,  but I did have fun converting it to utc time.  I learned that I was actually born a day earlier than I thought. 

Here’s the .aspx page:

 

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
    .textbox
    {
        width:100%;
        border:0;
        font-weight:bold;
        font-size:22px;
        overflow:hidden;
    }
    </style>

</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="TextBox1" runat="server" MaxLength="8"></asp:TextBox> - 
        <asp:TextBox ID="TextBox2" runat="server" MaxLength="4"></asp:TextBox> -
        <asp:TextBox ID="TextBox3" runat="server" MaxLength="4"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="Create Guid" 
            onclick="Button1_Click" /><br />
        <asp:TextBox ID="DisplayGuid" runat="server" CssClass="textbox" ></asp:TextBox>
        <asp:Label ID="Label1" runat="server"></asp:Label>
    </div>
    </form>
        <script type="text/javascript">
            if (document.getElementById('<%= DisplayGuid.ClientID %>').value != "")
            {
                document.getElementById('<%= DisplayGuid.ClientID %>').select();
                CopyToClipboard('<%= DisplayGuid.ClientID %>');

            }

function CopyToClipboard(controlId) 
{ 
    var control = document.getElementById(controlId); 

    if (control == null)
    {
        alert('ERROR – control not found – ' + controlId); 
    }
    else
    { 
        //determine the value of the control
        var controlValue = control.value; 

        //copy to clipboard 
        window.clipboardData.setData('Text', controlValue);
        alert('Copied GUID, ' + controlValue + ', to the clipboard.'); 
    }
} 

    </script>
</body>
</html>
The copy to clip board is starting to annoy me so it may come out.  I got it from http://grumpywookie.wordpress.com/2008/08/27/copy-to-clipboard-javascript/ 

I got the highlight piece from looking at the html source on this site http://createguid.com/  it wasn’t obvious that I could just hit ctrl-c and copy it.  But once you’re aware it’s kind of nice.  I might add parameters so that I can hit a link and always get the same prefix.

I really like the way Darren Hemming @cariad1234 was thinking about this. He called it a GUID namespace.  He brought up some valid points like it being a real GUID.  It’s run right through the new Guid() constructor so it’s a legitimate GUID, what are the chances of there being a duplicate in the world?  I don’t know.  But then again I don’t know what the chances are of an unseeded GUID.

Leave a comment or a trackback about how your are using your GUID!

  • Facebook
  • DZone It!
  • Digg It!
  • StumbleUpon
  • Technorati
  • Del.icio.us
  • NewsVine
  • Reddit
  • Blinklist
  • Furl it!

Comments (3)

  • Darren Hemming 6/9/2012 12:00:00 AM

    That's a beautiful and very quickly produced piece of code from poliTechnosis (Jim Wilcox). Adopting the Facebook style seeded guids makes real sense for large development companies trying to flag up which guids 'belong' to them.

    My notion of 'guid namespaces' is really just a variation on this theme, but with the increased use of sandbox solutions in SharePoint (especially in Office 365) I can see it becoming more and more important to identify which site columns/content types in a solution are custom, and which belong to Microsoft or some (large) third party. Almost everyone can write (sandbox) solutions for SharePoint now, which means that almost anyone can add new guid-referenced objects into sites and site collections.

    It's going to get pretty messy in those sites soon as sandbox developers start creating their own version of existing objects - there are already several variations on the Title site column available in SharePoint 2010; just standard ones from Microsoft. Imagine once sandbox developers cotton on to the fact that they can design and distribute their own content type 'collections'. We are bound to start seeing 'apps' in the SharePoint App store defining metadata taxonomies for countless verticals (medical, financial, legal, hospitality). I'm starting right now - dibs on the Welsh version of everything!

    Encouraging individuals/companies to build a namespace into their guids will hopefully make it easier to develop in this diverse ecosystem.  Not only will it greatly reduce the chances of one developer overwriting the structures of another (as the current random guid system attempts to do); it will also make it easier for developers to build on top of each other's taxonomies in a modular and object orientated way:

    "StacyDraper has a great Choice column for picking parts of the body. PoliTechnosis has a great Choice column for Types of Pain. If I include both their sandbox solutions as installation pre-requisites for my Diagnose Illness content type then I will save myself a lot of definition work and I can worry less about updates".

    As for whether using up 16 characters on a namespace reduces uniqueness; only in a purely mathematical sense. But surely the chances of  the first 16 characters of a 'normal' randomly generated guid happening to exactly match the name of a SharePoint developer in Vancouver, whose solutions happen to be deployed on your farm. are very small. And if the new guid is being created with a namespace, then it's probably illegal (in some states) to use somebody else's namespace inside it. 

    Stacy's idea of building the rest of the guid based on minutes since the developer's birth make conflicts even less likely. For large companies like Microsoft, using a company reference and a developer reference to form the namespace, with the rest of the guid seeded by a pseud-random variable relating to the developer such as Minutes Since Birth, would probably be a really good idea. For sandbox developers, maybe just a company namespace with the rest of the characters being randomly generated would probably do.  PoliTechnosis has already written a great script that we can now use to generate random but meaningful guids, but what we really need in my view is for Visual Studio 12 to have this built in as an option. 

  • Darren Hemming 6/10/2012 12:00:00 AM

    All SPWales guids will begin with 577a1e51. Look out for them in a site collection coming to you. Find them under rocks and in sandbox solutions.
  • Eli Robillard 3/5/2013 12:00:00 AM

    Thanks for posting, it's a good idea that everyone should hear (though I'm not so sure about generating the entire GUID). 

    MSFT uses the same strategy - all SP Feature GUIDs start with "OOB Feature": 00BFEA71. Here are a few more interesting observations of how MSFT composes GUIDs: http://notes.jonbeckett.com/2011/02/20/hidden-information-in-the-sharepoint-feature-guids/ 

    It's a great strategy to help people identify the source of work whether in the ULS logs or anywhere else, and it's worth getting every client to adopt some consistent prefix. And I can't remember where I first heard of it (though it was a SharePoint guy - the company was blue fox or shark or words to that effect) but he also suggested things like embedding project codes and major version numbers in GUIDs.

    Because I trust the GUIDGen algorithm and know it to be based on a few mathematical principles (even if I don't care what they are, maybe that's what you're duplicating here), I'll continue to use the VS GUIDGen tool and update its results with the chosen prefix, but again, glad you're spreading the word.

    Cheers,
    -Eli.
Post a comment!
  1. Formatting options
       
     
     
     
     
       



Rss Feed
    follow me on Twitter

    Where I'm Going

    Some Writing I've Done


    Chat With Me