2010-05-17 24 views
5

如果每次请求只需要一个数字,在ASP.NET MVC应用程序中生成随机数的正确方法是什么?根据MSDN的说法,为了获得足够的质量随机性,必须使用一次创建的单个System.Random对象生成多个数字。由于为MVC中的每个请求创建了一个控制器类的新实例,因此我无法使用在控制器的构造函数中为Random对象初始化的私有字段。那么,我应该创建和存储Random对象的哪个部分?目前,我把它存储在控制器类的静态字段,懒洋洋地初始化它在使用它的操作方法:MVC应用程序中的随机数生成

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    ... 

    public ActionResult Download() 
    { 
     ... 

     if (random == null) 
      random = new Random(); 

     ... 

    } 
} 

由于“随机”字段可以由控制器类的多个实例访问,是它如果两个实例试图同时初始化它的值,可能会损坏它的值?还有一个问题:我知道静态的生命周期是应用程序的生命周期,但是在MVC应用程序的情况下它是什么?它是从IIS启动直到IIS关机?

回答

10

理想情况下,您希望维护Random类的实例的时间长于单个页面的生命周期。做不是通过把它放在一个静态变量中做到这一点; Random类不是线程安全的,这会导致问题。从the docs

任何实例成员不保证是线程安全的。

我最喜欢的方法是从Microsoft ParallelFX队伍(谁真正知道他们正在使用的线程做什么)的RandomGen2包装类,它使用每线程一个实例(大部分)无锁,线程安全的随机数。

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local; 

    public static int Next() 
    { 
     Random inst = _local; 
     if (inst == null) 
     { 
      int seed; 
      lock (_global) seed = _global.Next(); 
      _local = inst = new Random(seed); 
     } 
     return inst.Next(); 
    } 
} 

然后您可以只是调用如下:

var rand = RandomGen2.Next(); 

您可能需要添加额外的方法来包装你要访问其他Random方法,我会建议一个更好的名字,例如作为ThreadSafeRandom,但它表明了原则。

1

您可以在HomeController中有一个静态构造函数来保存您不必在每种方法中对其进行延迟初始化。这几乎可以确保Random只被初始化一次(第一次被访问)。

public class HomeController : Controller 
{ 
    ... 

    private static Random random; 

    static HomeController() 
    { 
     random = new Random(); 
    } 

    ... 

    public ActionResult Download() 
    { 
     ... 

     //use random - its already created. 


     ... 

    } 
} 
2

除非你扔在一起的一些快速演示或什么的,我会把这个责任到服务或基础设施层(即,只是一个类),并让它管理您的随机数生成器的寿命。这不是真的是控制器的工作来管理这个 - 无论何时/如果您有另一个需要随机数的控制器,您都不会担心它。