Ich benötige eine eindeutige Kennung in .NET (kann die GUID nicht verwenden, da sie für diesen Fall zu lang ist).
Denken die Leute, dass der hier verwendete Algorithmus ein guter Kandidat ist, oder haben Sie andere Vorschläge?
Ich benötige eine eindeutige Kennung in .NET (kann die GUID nicht verwenden, da sie für diesen Fall zu lang ist).
Denken die Leute, dass der hier verwendete Algorithmus ein guter Kandidat ist, oder haben Sie andere Vorschläge?
Antworten:
Dies ist eine gute - http://www.singular.co.nz/blog/archive/2007/12/20/shortguid-a-shorter-and-url-friendly-guid-in-c-sharp.aspx
und auch hier YouTube-ähnliche GUID
Sie könnten Base64 verwenden:
string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());
Dadurch wird eine Zeichenfolge wie E1HKfn68Pkms5zsZsvKONw == generiert. Da eine GUID immer 128 Bit umfasst, können Sie das == weglassen, von dem Sie wissen, dass es immer am Ende vorhanden ist und das Ihnen eine 22-stellige Zeichenfolge gibt. Dies ist jedoch nicht so kurz wie YouTube.
Ich benutze einen ähnlichen Ansatz wie Dor Cohens, entferne aber einige Sonderzeichen:
var uid = Regex.Replace(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), "[/+=]", "");
Dies gibt nur alphanumerische Zeichen aus. Es ist nicht garantiert, dass die UIDs immer dieselbe Länge haben. Hier ist ein Probelauf:
vmKo0zws8k28fR4V4Hgmw
TKbhS0G2V0KqtpHOU8e6Ug
rfDi1RdO0aQHTosh9dVvw
3jhCD75fUWjQek8XRmMg
CQUg1lXIXkWG8KDFy7z6Ow
bvyxW5aj10OmKA5KMhppw
pIMK8eq5kyvLK67xtsIDg
VX4oljGWpkSQGR2OvGoOQ
NOHBjUUHv06yIc7EvotRg
iMniAuUG9kiGLwBtBQByfg
var ticks = new DateTime(2016,1,1).Ticks;
var ans = DateTime.Now.Ticks - ticks;
var uniqueId = ans.ToString("x");
Behalten Sie ein Basisdatum (in diesem Fall den 1. Januar 2016) bei, ab dem Sie mit der Generierung dieser IDs beginnen. Dadurch werden Ihre IDs kleiner.
Generierte Nummer: 3af3c14996e54
milliseconds
ist immer 0 für dieses DateTime
Objekt
Einfaches nutzbares Paket. Ich benutze es für den zeitlichen Anforderungs-ID-Generator.
https://www.nuget.org/packages/shortid
https://github.com/bolorundurowb/shortid
Verwendet System.Random
string id = ShortId.Generate();
// id = KXTR_VzGVUoOY
(von der Github-Seite)
Wenn Sie den Typ der generierten ID steuern möchten, indem Sie angeben, ob Sie Zahlen, Sonderzeichen und die Länge möchten, rufen Sie die Generate-Methode auf und übergeben Sie drei Parameter. Der erste ist ein Boolescher Wert, der angibt, ob Sie Zahlen möchten, der zweite ein Boolescher Wert, der angibt, ob Sie möchten Sonderzeichen, die letzte eine Zahl, die Ihre Längenpräferenz angibt.
string id = ShortId.Generate(true, false, 12);
// id = VvoCDPazES_w
Soweit ich weiß, ist es nicht garantiert einzigartig , nur einen Teil einer GUID zu entfernen - tatsächlich ist es alles andere als einzigartig.
Das kürzeste, was ich weiß, das globale Einzigartigkeit garantiert, wird in diesem Blog-Beitrag von Jeff Atwood vorgestellt . In dem verlinkten Beitrag beschreibt er mehrere Möglichkeiten, eine GUID zu verkürzen und sie am Ende über Ascii85-Codierung auf 20 Byte zu reduzieren .
Wenn Sie jedoch unbedingt eine Lösung benötigen, die nicht länger als 15 Byte ist, haben Sie leider keine andere Wahl, als etwas zu verwenden, von dem nicht garantiert wird, dass es global einzigartig ist.
IDENTITY-Werte sollten in einer Datenbank eindeutig sein, aber Sie sollten sich der Einschränkungen bewusst sein. Dies macht beispielsweise das Einfügen von Massendaten grundsätzlich unmöglich, was Sie verlangsamt, wenn Sie mit einer sehr großen Anzahl von Datensätzen arbeiten.
Möglicherweise können Sie auch einen Datums- / Zeitwert verwenden. Ich habe mehrere Datenbanken gesehen, in denen Datum und Uhrzeit als PK verwendet werden, und obwohl es nicht besonders sauber ist, funktioniert es. Wenn Sie die Einfügungen steuern, können Sie effektiv sicherstellen, dass die Werte im Code eindeutig sind.
Für meine lokale App verwende ich diesen zeitbasierten Ansatz:
/// <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;
}
Hier ist meine Lösung nicht sicher für Parallelität, nicht mehr von 1000 GUIDs pro Sekunde und threadsicher.
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;
}
Code nicht optimiert, nur Probe!.
UtcNow
für jede Millisekunde ein eindeutiger Tick-Wert zurückgegeben wird: Gemäß den Anmerkungen hängt die Auflösung vom System-Timer ab. Außerdem sollten Sie sicherstellen, dass sich die Systemuhr nicht rückwärts ändert! (Da die Antwort von user13971889 diese Frage an die Spitze meines Feeds gestoßen hat und ich diese Antwort kritisiert habe, sollte ich diese Kritik hier wiederholen.)
Wenn Ihre App nicht über ein paar MILLIIONEN Personen verfügt, die in der GLEICHEN MILLISECOND eine kurze, eindeutige Zeichenfolge generieren, können Sie über die Verwendung der folgenden Funktion nachdenken.
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());
}
Ändern Sie JJJJ in JJ, wenn Sie Ihre App in den nächsten 99 Jahren nur noch verwenden müssen.
Update 20160511 : Richtig Zufallsfunktion
- Hinzufügen Objekt sperren
- Move Zufallsvariable aus Randomfunktion
Ref
lock
ist, dass Sie dieselbe Random
Instanz wiederverwenden können . Ich denke, Sie haben vergessen, diese Zeile zu löschen!
Ich weiß, dass es ziemlich weit vom veröffentlichten Datum entfernt ist ... :)
Ich habe einen Generator, der nur 9 Hexa-Zeichen erzeugt , zB: 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");
}
}
Basierend auf der Antwort von @ dorcohen und dem Kommentar von @ pootzko. Sie können dies verwenden. Es ist sicher über den Draht.
var errorId = System.Web.HttpServerUtility.UrlTokenEncode(Guid.NewGuid().ToByteArray());
Jzhw2oVozkSNa2IkyK4ilA2
oder versuchen Sie es unter dotnetfiddle.net/VIrZ8j
Basierend auf einigen anderen ist hier meine Lösung, die eine andere codierte Richtlinie bereitstellt, die URL- (und Docker-) sicher ist und keine Informationen verliert:
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("=", "").Replace("+", "-").Replace("/", "_");
Beispielausgaben sind:
BcfttHA780qMdHSxSBoZFA
_4p5srPgOE2f25T_UnoGLw
H9xR_zdfm0y-zYjdR3NOig
In C # hat ein long
Wert 64 Bit. Wenn er mit Base64 codiert wird, gibt es 12 Zeichen, einschließlich 1 Auffüllung =
. Wenn wir die Polsterung kürzen =
, gibt es 11 Zeichen.
Eine verrückte Idee hier ist, dass wir eine Kombination aus Unix-Epoche und einem Zähler für einen Epochenwert verwenden könnten, um einen Wert zu bilden long
. Die Unix-Epoche in C # DateTimeOffset.ToUnixEpochMilliseconds
hat das long
Format, aber die ersten 2 Bytes der 8 Bytes sind immer 0, da sonst der Datums- / Uhrzeitwert größer als der maximale Datums- / Uhrzeitwert ist. Das gibt uns also 2 Bytes, in die wir einen ushort
Zähler einfügen können.
Insgesamt können wir also eine eindeutige ID haben, solange die Anzahl der ID-Generierungen 65536 pro Millisekunde nicht überschreitet:
// 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('=');
Wenn Sie die Zeichenfolge nicht eingeben müssen, können Sie Folgendes verwenden:
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());
}
Dadurch wird die Guid in eine 8-stellige Zeichenfolge wie folgt konvertiert:
{b77a49a5-182b-42fa-83a9-824ebd6ab58d} -> "䦥 띺 ᠫ 䋺 ꦃ 亂 檽 趵"
{c5f8f7f5-8a7c-4511-b667-8ad36b446617} -> " 엸 詼 䔑 架 펊 䑫 ᝦ"
Hier ist meine kleine Methode, um eine zufällige und kurze eindeutige ID zu generieren. Verwendet ein kryptografisches Rng zur sicheren Erzeugung von Zufallszahlen. Fügen Sie der chars
Zeichenfolge die erforderlichen Zeichen hinzu .
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);
}
Um keine Zeichen (+ / -) zu verlieren und wenn Sie Ihre Guid in einer URL verwenden möchten, muss sie in base32 umgewandelt werden
für 10 000 000 kein doppelter Schlüssel
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;
}
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)
}
Verwendung
Guid.NewGuid().ToTinyUuid()
Es ist keine Raketenwissenschaft, zurück zu konvertieren, also werde ich dich so sehr verlassen.
Sie können es mit der folgenden Bibliothek versuchen:
private static readonly object _getUniqueIdLock = new object();
public static string GetUniqueId()
{
lock(_getUniqueIdLock)
{
System.Threading.Thread.Sleep(1);
return DateTime.UtcNow.Ticks.ToString("X");
}
}
UtcNow
für jede Millisekunde ein eindeutiger Tick-Wert zurückgegeben wird: Gemäß den Anmerkungen hängt die Auflösung vom System-Timer ab. Außerdem sollten Sie sicherstellen, dass sich die Systemuhr nicht rückwärts ändert! (Die Antwort von ur3an0 hat auch diese Probleme.)
Sie können verwenden
code = await UserManager.GenerateChangePhoneNumberTokenAsync(input.UserId, input.MobileNumber);
seine 6
nur schöne Zeichen, 599527
,143354
und wenn Benutzer es einfach virifizieren
var result = await UserManager.VerifyChangePhoneNumberTokenAsync(input.UserId, input.Token, input.MobileNumber);
hoffe das hilft dir
Guid.NewGuid().ToString().Split('-').First()
Ich benutze Guid.NewGuid().ToString().Split('-')[0]
, es bekommt das erste Element aus dem Array durch das '-' getrennt. Es ist genug, um einen eindeutigen Schlüssel darzustellen.