germi's answer is slightly misleading as it implies that any repeated instantiation of a new Random will produce the same sequence of values. This isn't quite correct, because your debug code works as you expect.
The documentation for Random says that the Random number generator is seeded from the system clock if you dont pass a seed value. https://learn.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=netframework-4.8
The reason it works in debug is that debugging code is very slow (you're literally taking hundreds of milliseconds to step through the code a line at a time) and the clock has time to change in between runs of the loop.
When your code is run at full speed it runs so quickly that the system clock simply won't have changed to a new milliseconds value, so your repeated making of a new Random will result in it being seeded with the same value from the clock
If you were to insert some delay in the code such as Thread.Sleep(1000) in the loop then it would work. If you were to run the loop a million times it would take long enough to work through that the clock would eventually change - a million iterations might take long enough for a small handful of values to come out of the Random
The recommendation for a solution is sound though; make one new Random somewhere outside of the loop and then repeatedly call it. You could also seed the Random with something that is unique each time (like the value of i), though you should bear in mind that providing a particular seed will guarantee that the same random number comes out of it when you call Next. In some contexts this is useful, because you might want a situation where you can provide a certain value and then see the same sequence of random numbers emerge. The main thing to be mindful of is that by default the Random starts it's sequence based on the clock; two different computers with different time settings can theoretically produce the same random numbers if their clocks are reading the same at the moment the Random is created.