According to following code , I need to generate a string in different cases based on the method input. My issue is where I wanna generate 9A9A (at least 1 number and 1 letter) or 9A9A9A (at least 2 numbers and 2 letters). In most cases, this conditions is not met.
private AuthMessage GetAuthCode(string CodeType) //(out string Message)
{
Guid Guid = Guid.NewGuid();
Random Random = new Random();
string AuthCode = string.Empty;
string RefCode = string.Empty;
RefCode = Guid.ToString("N");
switch (CodeType)
{
case "0": //9999
{
AuthCode = Random.Next(1000, 9999).ToString();
break;
}
case "1": //99999
{
AuthCode = Random.Next(10000, 99999).ToString();
break;
}
case "2": //999999
{
AuthCode = Random.Next(100000, 999999).ToString();
break;
}
case "3": //999-999
{
AuthCode = Regex.Replace(Random.Next(100000, 999999).ToString(), @"^(.{3})(.{3})$", "$1-$2");
break;
}
case "4": //9A9A
{
AuthCode = Guid.ToString("N").Substring(14, 4).ToUpper();
break;
}
case "5": //9A9A9
{
AuthCode = Guid.ToString("N").Substring(15, 5).ToUpper();
break;
}
case "6": //9A9A9A
{
AuthCode = Guid.ToString("N").Substring(6, 6).ToUpper();
break;
}
case "7": //9A9-A9A
{
AuthCode = Regex.Replace(Guid.ToString("N").Substring(6, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
break;
}
case "8": //9A9-A9A
{
AuthCode = Regex.Replace(Regex.Replace(Convert.ToBase64String(Guid.ToByteArray()), "[/+=]", "").Substring(0, 6), @"(.{3})(.{3})", @"$1-$2").ToUpper();
break;
}
default:
{
AuthCode = Random.Next(1000, 9999).ToString();
break;
}
}
AuthMessage Response = new AuthMessage();
Response.AuthCode = AuthCode;
Response.RefCode = RefCode;
return Response;
}
Guid representation is composed of hexadecimal digits, i.e. characters 0-9 and a-f. The problem with relying on it to obtain a mixture of letters and numbers is that a character at any given position could be either a letter or a decimal digit, with probability tilted roughly 5:3 in favor of a decimal digit.
If you want to generate a specific mix of digits and letters, you should generate the string one character at a time, without relying on Guid representation.
I thought I'd have a go - it gives me a good chance of being ridiculed. This isn't the most efficient way of generating the codes, but it should be fairly random.
private string GetAuthCode(string CodeType)
{
var patterns = new Dictionary<char, Func<Char>>()
{
{ '9', () => RandomBytes().Where(x => x >= '0' && x <= '9').First() },
{ 'A', () => RandomBytes().Where(x => x >= 'A' && x <= 'Z').First() },
{ '-', () => '-' },
};
return
String.IsNullOrEmpty(CodeType)
? ""
: patterns[CodeType[0]]().ToString() + GetAuthCode(CodeType.Substring(1));
}
private IEnumerable<char> RandomBytes()
{
using (var rng = System.Security.Cryptography.RNGCryptoServiceProvider.Create())
{
var bytes = new byte[256];
while (true)
{
rng.GetBytes(bytes);
foreach (var @byte in bytes)
{
yield return (char)@byte;
}
}
}
}
Now, due to the funky monkey state machine that implements iterator methods, this code does dispose of the RNG despite the while (true).
I simplified the GetAuthCode method slightly, but I think this demonstrates a suitable way to generate the codes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With