Since RNGRandomNumberGenerator only returns byte arrays, you have to do it like this:
static string RandomString(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] uintBuffer = new byte[sizeof(uint)];
while (length-- > 0)
{
rng.GetBytes(uintBuffer);
uint num = BitConverter.ToUInt32(uintBuffer, 0);
res.Append(valid[(int)(num % (uint)valid.Length)]);
}
}
return res.ToString();
}
Note however that this has a flaw, 62 valid characters is equal to 5,9541963103868752088061235991756 bits (log(62) / log(2)), so it won’t divide evenly on a 32 bit number (uint).
What consequences does this have?
As a result, the random output won’t be uniform. Characters which are lower in value will occur more likely (just by a small fraction, but still it happens).
To be more precise, the first 4 characters of a valid array are 0,00000144354999199840239435286 % more likely to occur.
To avoid this, you should use array lengths that will divide evenly into 64 (Consider using Convert.ToBase64String on the output instead, since you can cleanly match 64 bits to 6 bytes.