Necesito un identificador único en .NET (no puedo usar GUID porque es demasiado largo para este caso).
¿Piensa la gente que el algoritmo utilizado aquí es un buen candidato o tiene alguna otra sugerencia?
c#
.net
uniqueidentifier
Navidad
fuente
fuente
Respuestas:
Este es uno bueno: http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx
y también aquí GUID similar a YouTube
Podrías usar Base64:
string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
fuente
Utilizo un enfoque similar al de Dor Cohen pero eliminando algunos caracteres especiales:
var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
Esto generará solo caracteres alfanuméricos. No se garantiza que los UID tengan siempre la misma longitud. Aquí hay una muestra de ejecución:
vmKo0zws8k28fR4V4Hgmw TKbhS0G2V0KqtpHOU8e6Ug rfDi1RdO0aQHTosh9dVvw 3jhCD75fUWjQek8XRmMg CQUg1lXIXkWG8KDFy7z6Ow bvyxW5aj10OmKA5KMhppw pIMK8eq5kyvLK67xtsIDg VX4oljGWpkSQGR2OvGoOQ NOHBjUUHv06yIc7EvotRg iMniAuUG9kiGLwBtBQByfg
fuente
var ticks = new DateTime(2016,1,1).Ticks; var ans = DateTime.Now.Ticks - ticks; var uniqueId = ans.ToString("x");
Mantenga una fecha de referencia (que en este caso es el 1 de enero de 2016) a partir de la cual comenzará a generar estos identificadores. Esto hará que sus identificadores sean más pequeños.
Número generado: 3af3c14996e54
fuente
milliseconds
es siempre 0 para eseDateTime
objetoPaquete utilizable simple. Lo uso para el generador de ID de solicitud temporal.
https://www.nuget.org/packages/shortid
https://github.com/bolorundurowb/shortid
Usos
System.Random
string id = ShortId.Generate(); // id = KXTR_VzGVUoOY
(de la página de github)
Si desea controlar el tipo de identificación generada especificando si desea números, caracteres especiales y la longitud, llame al método Generate y pase tres parámetros, el primero un booleano que indique si desea números, el segundo un booleano que indique si desea caracteres especiales, el último un número que indica su preferencia de longitud.
string id = ShortId.Generate(true, false, 12); // id = VvoCDPazES_w
fuente
Hasta donde yo sé, no se garantiza que simplemente eliminar una parte de un GUID sea único ; de hecho, está lejos de ser único.
Lo más breve que sé que garantiza la singularidad global se presenta en esta publicación de blog de Jeff Atwood . En la publicación vinculada, analiza varias formas de acortar un GUID y, al final, lo reduce a 20 bytes a través de la codificación Ascii85 .
Sin embargo, si absolutamente necesita una solución que no tenga más de 15 bytes, me temo que no tiene otra opción que usar algo que no esté garantizado como único a nivel mundial.
fuente
Los valores de IDENTIDAD deben ser únicos en una base de datos, pero debe tener en cuenta las limitaciones ... por ejemplo, hace que las inserciones de datos masivos sean básicamente imposibles, lo que lo ralentizará si está trabajando con una gran cantidad de registros.
También puede utilizar un valor de fecha / hora. He visto varias bases de datos donde usan la fecha / hora para ser el PK, y aunque no es súper limpio, funciona. Si controla las inserciones, puede garantizar efectivamente que los valores serán únicos en el código.
fuente
Para mi aplicación local, estoy usando este enfoque basado en el tiempo:
/// <summary> /// Returns all ticks, milliseconds or seconds since 1970. /// /// 1 tick = 100 nanoseconds /// /// Samples: /// /// Return unit value decimal length value hex length /// -------------------------------------------------------------------------- /// ticks 14094017407993061 17 3212786FA068F0 14 /// milliseconds 1409397614940 13 148271D0BC5 11 /// seconds 1409397492 10 5401D2AE 8 /// /// </summary> public static string TickIdGet(bool getSecondsNotTicks, bool getMillisecondsNotTicks, bool getHexValue) { string id = string.Empty; DateTime historicalDate = new DateTime(1970, 1, 1, 0, 0, 0); if (getSecondsNotTicks || getMillisecondsNotTicks) { TimeSpan spanTillNow = DateTime.UtcNow.Subtract(historicalDate); if (getSecondsNotTicks) id = String.Format("{0:0}", spanTillNow.TotalSeconds); else id = String.Format("{0:0}", spanTillNow.TotalMilliseconds); } else { long ticksTillNow = DateTime.UtcNow.Ticks - historicalDate.Ticks; id = ticksTillNow.ToString(); } if (getHexValue) id = long.Parse(id).ToString("X"); return id; }
fuente
aquí mi solución, no es segura para la concurrencia, no más de 1000 GUID por segundo y seguro para subprocesos.
public static class Extensors { private static object _lockGuidObject; public static string GetGuid() { if (_lockGuidObject == null) _lockGuidObject = new object(); lock (_lockGuidObject) { Thread.Sleep(1); var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); var epochLong = Convert.ToInt64((DateTime.UtcNow - epoch).TotalMilliseconds); return epochLong.DecimalToArbitrarySystem(36); } } /// <summary> /// Converts the given decimal number to the numeral system with the /// specified radix (in the range [2, 36]). /// </summary> /// <param name="decimalNumber">The number to convert.</param> /// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param> /// <returns></returns> public static string DecimalToArbitrarySystem(this long decimalNumber, int radix) { const int BitsInLong = 64; const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (radix < 2 || radix > Digits.Length) throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString()); if (decimalNumber == 0) return "0"; int index = BitsInLong - 1; long currentNumber = Math.Abs(decimalNumber); char[] charArray = new char[BitsInLong]; while (currentNumber != 0) { int remainder = (int)(currentNumber % radix); charArray[index--] = Digits[remainder]; currentNumber = currentNumber / radix; } string result = new String(charArray, index + 1, BitsInLong - index - 1); if (decimalNumber < 0) { result = "-" + result; } return result; }
código no optimizado, solo muestra !.
fuente
UtcNow
devuelva un valor de tic único por cada milisegundo: según los comentarios , la resolución depende del temporizador del sistema. Además, ¡será mejor que se asegure de que el reloj del sistema no cambie hacia atrás! (Dado que la respuesta del usuario 13971889 colocó esta pregunta en la parte superior de mi feed y critiqué esa respuesta, creo que debería repetir esa crítica aquí).Si su aplicación no tiene unos pocos MILLONES de personas, usando esa cadena de generación única y corta en el MISMO MILISEGUNDO, puede pensar en usar la siguiente función.
private static readonly Object obj = new Object(); private static readonly Random random = new Random(); private string CreateShortUniqueString() { string strDate = DateTime.Now.ToString("yyyyMMddhhmmssfff"); string randomString ; lock (obj) { randomString = RandomString(3); } return strDate + randomString; // 16 charater } private string RandomString(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; var random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); }
cambie yyyy a yy si solo necesita usar su aplicación en los próximos 99 años.
Actualización 20160511 : Función aleatoria correcta
- Agregar objeto de bloqueo
- Mover variable aleatoria fuera de la función RandomString
Ref
fuente
lock
es permitirle reutilizar la mismaRandom
instancia. ¡Creo que olvidaste borrar esa línea!Sé que está bastante lejos de la fecha de publicación ... :)
Tengo un generador que produce solo 9 caracteres Hexa , por ejemplo: C9D6F7FF3, C9D6FB52C
public class SlimHexIdGenerator : IIdGenerator { private readonly DateTime _baseDate = new DateTime(2016, 1, 1); private readonly IDictionary<long, IList<long>> _cache = new Dictionary<long, IList<long>>(); public string NewId() { var now = DateTime.Now.ToString("HHmmssfff"); var daysDiff = (DateTime.Today - _baseDate).Days; var current = long.Parse(string.Format("{0}{1}", daysDiff, now)); return IdGeneratorHelper.NewId(_cache, current); } } static class IdGeneratorHelper { public static string NewId(IDictionary<long, IList<long>> cache, long current) { if (cache.Any() && cache.Keys.Max() < current) { cache.Clear(); } if (!cache.Any()) { cache.Add(current, new List<long>()); } string secondPart; if (cache[current].Any()) { var maxValue = cache[current].Max(); cache[current].Add(maxValue + 1); secondPart = maxValue.ToString(CultureInfo.InvariantCulture); } else { cache[current].Add(0); secondPart = string.Empty; } var nextValueFormatted = string.Format("{0}{1}", current, secondPart); return UInt64.Parse(nextValueFormatted).ToString("X"); } }
fuente
Basado en la respuesta de @ dorcohen y el comentario de @ pootzko. Puedes usar esto. Es seguro sobre el cable.
var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
fuente
Jzhw2oVozkSNa2IkyK4ilA2
o pruebe usted mismo en dotnetfiddle.net/VIrZ8jBasado en algunos otros, aquí está mi solución que proporciona un guid codificado diferente que es seguro para URL (y Docker) y no pierde ninguna información:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("=", "").Replace("+", "-").Replace("/", "_");
Los resultados de ejemplo son:
fuente
En C #, un
long
valor tiene 64 bits, que si se codifica con Base64, habrá 12 caracteres, incluido 1 relleno=
. Si recortamos el relleno=
, habrá 11 caracteres.Una idea loca aquí es que podríamos usar una combinación de Unix Epoch y un contador para un valor de época para formar un
long
valor. El Unix Epoch en C #DateTimeOffset.ToUnixEpochMilliseconds
está enlong
formato, pero los primeros 2 bytes de los 8 bytes son siempre 0, porque de lo contrario el valor de fecha y hora será mayor que el valor máximo de fecha y hora. Entonces eso nos da 2 bytes para colocar unushort
contador.Entonces, en total, siempre que el número de generación de ID no exceda 65536 por milisegundo, podemos tener una ID única:
// This is the counter for current epoch. Counter should reset in next millisecond ushort currentCounter = 123; var epoch = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // Because epoch is 64bit long, so we should have 8 bytes var epochBytes = BitConverter.GetBytes(epoch); if (BitConverter.IsLittleEndian) { // Use big endian epochBytes = epochBytes.Reverse().ToArray(); } // The first two bytes are always 0, because if not, the DateTime.UtcNow is greater // than DateTime.Max, which is not possible var counterBytes = BitConverter.GetBytes(currentCounter); if (BitConverter.IsLittleEndian) { // Use big endian counterBytes = counterBytes.Reverse().ToArray(); } // Copy counter bytes to the first 2 bytes of the epoch bytes Array.Copy(counterBytes, 0, epochBytes, 0, 2); // Encode the byte array and trim padding '=' // e.g. AAsBcTCCVlg var shortUid = Convert.ToBase64String(epochBytes).TrimEnd('=');
fuente
public static string ToTinyUuid(this Guid guid) { return Convert.ToBase64String(guid.ToByteArray())[0..^2] // remove trailing == padding .Replace('+', '-') // escape (for filepath) .Replace('/', '_'); // escape (for filepath) }
Uso
No es ciencia espacial volver a convertir, así que les dejo eso.
fuente
Si no necesita escribir la cadena, puede usar lo siguiente:
static class GuidConverter { public static string GuidToString(Guid g) { var bytes = g.ToByteArray(); var sb = new StringBuilder(); for (var j = 0; j < bytes.Length; j++) { var c = BitConverter.ToChar(bytes, j); sb.Append(c); j++; } return sb.ToString(); } public static Guid StringToGuid(string s) => new Guid(s.SelectMany(BitConverter.GetBytes).ToArray()); }
Esto convertirá el Guid en una cadena de 8 caracteres como esta:
{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "䦥 띺 ᠫ 䋺 ꦃ 亂 檽 趵"
{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> " 엸 詼 䔑 架 펊 䑫 ᝦ"
fuente
Aquí está mi pequeño método para generar una identificación única aleatoria y corta. Utiliza un rng criptográfico para la generación segura de números aleatorios. Agregue los caracteres que necesite a la
chars
cadena.private string GenerateRandomId(int length) { char[] stringChars = new char[length]; byte[] randomBytes = new byte[length]; using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { rng.GetBytes(randomBytes); } string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; for (int i = 0; i < stringChars.Length; i++) { stringChars[i] = chars[randomBytes[i] % chars.Length]; } return new string(stringChars); }
fuente
para no perder caracteres (+ / -) y si quieres usar tu guid en una url, debes transformarlo en base32
por 10000000 sin llave duplicada
public static List<string> guids = new List<string>(); static void Main(string[] args) { for (int i = 0; i < 10000000; i++) { var guid = Guid.NewGuid(); string encoded = BytesToBase32(guid.ToByteArray()); guids.Add(encoded); Console.Write("."); } var result = guids.GroupBy(x => x) .Where(group => group.Count() > 1) .Select(group => group.Key); foreach (var res in result) Console.WriteLine($"Duplicate {res}"); Console.WriteLine($"*********** end **************"); Console.ReadLine(); } public static string BytesToBase32(byte[] bytes) { const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; string output = ""; for (int bitIndex = 0; bitIndex < bytes.Length * 8; bitIndex += 5) { int dualbyte = bytes[bitIndex / 8] << 8; if (bitIndex / 8 + 1 < bytes.Length) dualbyte |= bytes[bitIndex / 8 + 1]; dualbyte = 0x1f & (dualbyte >> (16 - bitIndex % 8 - 5)); output += alphabet[dualbyte]; } return output; }
fuente
Puedes probar con la siguiente biblioteca:
fuente
private static readonly object _getUniqueIdLock = new object(); public static string GetUniqueId() { lock(_getUniqueIdLock) { System.Threading.Thread.Sleep(1); return DateTime.UtcNow.Ticks.ToString("X"); } }
fuente
UtcNow
devuelva un valor de tic único por cada milisegundo: según los comentarios , la resolución depende del temporizador del sistema. Además, ¡será mejor que se asegure de que el reloj del sistema no cambie hacia atrás! (La respuesta de ur3an0 también tiene estos problemas.)puedes usar
code = await UserManager.GenerateChangePhoneNumberTokenAsync(input.UserId, input.MobileNumber);
solo sus
6
personajes agradables599527
,143354
y cuando el usuario lo virifica simplemente
var result = await UserManager.VerifyChangePhoneNumberTokenAsync(input.UserId, input.Token, input.MobileNumber);
espero que esto te ayude
fuente
Guid.NewGuid().ToString().Split('-').First()
fuente