Summary#
Random.Next answers a random integer, spelled exactly as C#'s System.Random.Next.
int n = Random.Next(10); // 0..9 — max is EXCLUSIVE, as in C#
int d = Random.Next(1, 7); // 1..6 — min inclusive, max exclusiveThere are two randoms in this platform and choosing between them is the whole of what you need to know:
| you want | use | why |
|---|---|---|
| a number, a pick, a shuffle, a jitter | Random.Next | ordinary, fast, and reproducible under a test seed |
| a token, a reset code, an api key, a session id | Security.RandomId / RandomHex | cryptographic — see Security.* — hashing, verifying, tickets, random ids |
Signature#
int Random.Next() // any non-negative int — the ordering form
int Random.Next(int max) // [0, max) — `max` must be at least 1
int Random.Next(int min, int max) // [min, max) — `max` must be greater than `min`An empty range has no value to answer with, so it is refused rather than answered: Random.Next(0) and
Random.Next(5, 5) both throw, naming the bound. Random.Next(list.Count) over an empty list is the usual way to
reach that, so check the count first.
Description#
It is seedable, and that is not an implementation detail. A test that draws must be able to draw the same sequence twice, or it can only assert statistically — "at least 25 of 40 were idle" — which is slow and flaky by construction. Seeding is what makes an exact assertion possible.
And that is exactly why it must not make a secret. A value anyone can reproduce is not unguessable. The
sequence is predictable from any earlier value, and nothing about the result looks wrong: it is not obviously
sequential, the tests pass, and it stays guessable until somebody enumerates it. C# draws this same line between
System.Random and RandomNumberGenerator, and gets the same misuse.
security-weak-random is a MUST-tier lint on exactly that mistake — a Random draw landing in a member named for
a credential (token, secret, password, apiKey, nonce, otp, …). It fires on the DESTINATION, never on
the call, because Random.Next is correct nearly everywhere.
It works inside a LINQ query#
Random.Next() is translated to SQL, so it is usable anywhere in a query — not only in a function body. There
is no separate OrderByRandom() verb to learn, and none is needed: it is an ordinary OrderBy over an ordinary
call, which is what a C# author writes, and it therefore composes with ThenBy, Where, Take and the rest
exactly as any other sort key does.
This is how you take one row at random without a Count() and a Skip():
// one row at random — ONE round trip
Film any = Film.OrderBy(f => Random.Next()).Take(1).FirstOrDefault();
// the shape most selection rules actually take: least-compared, RANDOM AMONG TIES
Film pick = Film.OrderBy(f => f.Comparisons)
.ThenBy(f => Random.Next())
.Take(1).FirstOrDefault();The second is the one worth knowing. Without a random tiebreak, "the least-compared film" returns the same film every time two are tied, so a matchmaker walks the same pair repeatedly. With it, the primary sort still decides and the tie is broken fairly, in one query.
It runs in the DATABASE, not in the browser and not in memory — ORDER BY random() — so the whole draw is one
round trip whatever the table's size. A .Where(…) before it narrows the rows the database is choosing among, as
you would expect:
Film pick = Film.Where(f => !f.Watched)
.OrderBy(f => Random.Next())
.Take(1).FirstOrDefault();⚠ Not inside a live var. A reactive read re-runs whenever its inputs change, and a random order returns a
different row each time — so the value flickers when something unrelated moves. Draw in an action, store what you
drew, and let the page read the stored row.
Examples#
entity Card { [Required, MaxLength(40)] string Face;
security { allow read, create when IsAnonymous || IsAuthenticated; } }
// One of a known set, chosen at random.
string DealOne() {
var faces = ["clubs", "diamonds", "hearts", "spades"];
return faces[Random.Next(faces.Count)];
}
// A retry jitter — spread out so a hundred clients do not return at the same instant.
int BackoffMillis(int attempt) { return 500 * attempt + Random.Next(250); }See also#
- Security.* — hashing, verifying, tickets, random ids —
RandomId/RandomHex, the cryptographic pair, for anything a stranger must not guess.