2

Is there a way to generate unique alphanumeric key (12 digits) to be used in URLs in C#? I have a set of strings that are unique from each other, but cannot use them directly as they might change, so the URL will break. I have couple of approaches -

a) Use the primary key of database table itself which corresponds to the row with above set of strings, but this seems like a security issue as it will expose db structure.

b) Use Guid, but then again it is not dependent on the data.

Any help will be appreciated.

Sam
  • 4,302
  • 12
  • 40
  • 74
  • Must it be unique or just pseudo-unique? Even a `GUID` is not unique just practically so. http://stackoverflow.com/questions/1705008/simple-proof-that-guid-is-not-unique – Shaun Luttin Mar 29 '15 at 19:44
  • This might be a duplicate: http://stackoverflow.com/questions/5566602/how-to-generate-unique-alphanumeric – Shaun Luttin Mar 29 '15 at 19:46
  • That is another reason I don't wish to use Guid as it has to be used in link which must be unique for obvious reasons. – Sam Mar 29 '15 at 19:46
  • 2
    If it just needs to be unique within your database, then using the primary key but hashing it (or some similar process) might be a good approach. – Shaun Luttin Mar 29 '15 at 19:48

3 Answers3

4

Short Answer: No.

What you're trying is not possible. You would have to keep track of the ids that you've already created. This is what a database does with index columns that increment. I also understand that URL shortening tools take new keys from a pool of generated unique ones.

All that being said, something like this DotNetFiddle might work and so might some of the other answers.

In the fiddle, we're hashing the primary key in the first example. Since only the full hash is computationally infeasible not to be unique per input, and since we're using a sub-string of the hash, the uniqueness is not guaranteed, but it may be close.

Here is what MSDN has to say about hash uniqueness.

A cryptographic hash function has the property that it is computationally infeasible to find two distinct inputs that hash to the same value.

In the second example, we're using time, and incrementing time is guaranteed to be unique as far as I know, so this will work if you can rely on the time being accurate. But if you're going to be relying on an external resource like the server time, then maybe you should be using an auto-incrementing index in a database table or a simple flat file.

using System;
using System.Text;
using System.Security.Cryptography;

public class Program
{
    public static void Main()
    {
        UseAHash();
        UseTime();
    }

    public static void UseAHash()
    {
        var primaryKey = 123345;
        HashAlgorithm algorithm = SHA1.Create();
        var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(primaryKey.ToString()));
        StringBuilder sb = new StringBuilder();
        for (var i = 0; i < 6; ++i)
        {
            sb.Append(hash[i].ToString("X2"));
        }

        Console.WriteLine(sb);
    }

    public static void UseTime()
    {
        StringBuilder builder = new StringBuilder();

        // use universal to avoid daylight to standard time change.
        var now = DateTime.Now.ToUniversalTime();

        builder.Append(now.DayOfYear.ToString("D3"));
        builder.Append(now.Hour.ToString("D2"));
        builder.Append(now.Minute.ToString("D2"));
        builder.Append(now.Second.ToString("D2"));
        builder.Append(now.Millisecond.ToString("D3"));

        Console.WriteLine("Length: " + builder.Length);
        Console.WriteLine("Result: " + builder);
    }
}
Community
  • 1
  • 1
Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
2

You can use the key from the database to seed a random generator, and use that to create a key:

int id = 42;
string chars = "2345679abcdefghjkmnpqrstuvwxyz";

Random rnd = new Random(id);
string key = new String(Enumerable.Range(0, 12).Select(n => chars[rnd.Next(chars.Length)]).ToArray());

Note: This is not guaranteed to be unique. I tested the values from 1 to 10000000 though, and there are no duplicates there.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Out of pure curiosity, do you know whether this would have a lower or higher chance of creating unique 12 character strings, compared to the approach using an SHA1 hash of primary keys, and then taking the first 12 characters? – Shaun Luttin Mar 29 '15 at 20:05
  • 2
    @ShaunLuttin: The hash code is specifically designed to give a good distribution, so generally that would give you a lower risk for collisions. – Guffa Mar 29 '15 at 20:14
0

Simple. Create a new GUID, assign it an entity from the database, then add it to a database table.

public class FooGuid
{
    [Key] public Guid Url { get; set; }
    public Foo Foo { get; set; }
}

Guid urlpart = ...
Foo foo = dbContext.FooGuids
              .Where(f => f.Url == urlpart)
              .Select(f => f.Foo)
              .Single();
Aron
  • 15,464
  • 3
  • 31
  • 64