Resizing a discrete uniform CSRNG distribution
There are things you can do to improve the efficiency of your filter solution with small values as the limit.

More efficient filtering

The most obvious one is actually given in the example of the function on the MSDN network - which is basically to extend the filter range to the highest multiple of limit, less than 256. I.e. if the limit is 20, then filter up to 240, and then the modulo is still uniformly distributed:

Copied from that page:


private static bool IsFairRoll(byte roll, byte numSides)
{
    // There are MaxValue / numSides full sets of numbers that can come up
    // in a single byte.  For instance, if we have a 6 sided die, there are
    // 42 full sets of 1-6 that come up.  The 43rd set is incomplete.
    int fullSetsOfValues = Byte.MaxValue / numSides;

    // If the roll is within this range of fair values, then we let it continue.
    // In the 6 sided die case, a roll between 0 and 251 is allowed.  (We use
    // &lt; rather than &lt;= since the = portion allows through an extra 0 value).
    // 252 through 255 would provide an extra 0, 1, 2, 3 so they are not fair
    // to use.
    return roll &lt; numSides * fullSetsOfValues;
}



Statistically insignificant errors

You have another alternative too, which is to reduce any modulo bias to a statistically insignificant amount. You do this by using significantly bigger random numbers (bigger than 256). Combining multiple bytes for each output byte would accomplish this, for example, using 4 bytes. Using more bytes would further reduce any modulo bias:

/* Convert 4 bytes to a long */
private static IEnumerable&lt;long&gt; RandomLongs()
{
    var csrng = new RNGCryptoServiceProvider();
    return Cycle().Select(unused =&gt;
    {
        var bytes = new byte[4];
        csrng.GetBytes(bytes);
        return  (long)(BitConverter.ToUInt32( bytes, 0));
    });
}

private static IEnumerable&lt;int&gt; RandomExtended(int chunkSize, int limit)
{
    var source = RandomBytes(chunkSize);
    foreach (long lng in RandomLongs())
    {
        var nxt = lng % limit;
        yield return (int)nxt;
    }

}   


Using 4 bytes of source for your modulo (with max limit 256) will reduce the bias error to about 1 in \$2^{24}\$ ... which would be hard to measure.

This version is also shown here on ideone: https://ideone.com/maiQ70

Removed


On the other hand, there's a better way, that still guarantees uniform distribution, but relies on knowing what the previous value was. Conceptually, this solution relies on having uniform "gaps" between results, and so you can add a uniform random gap to the previous value, and then do the modulo on that.

I implemented it as:

private static IEnumerable&lt;int&gt; RandomWrap(int chunkSize, int limit)
{
    int prev = 0;
    foreach (byte b in RandomBytes(chunkSize))
    {
        prev = (prev + b) % limit;
        yield return prev;
    }

}


Note that it takes the byte-value as a "gap", adds it to the previous result, and then "wraps" it around in the limit range.

You can see the results here in ideone: https://ideone.com/BEbwsA