为什么这种方法会向不同的用户吐出相同的结果

时间:2011-09-07 16:18:33

标签: c# asp.net random itextsharp

所以我有生成条形码和标签的方法。我们注意到,当多个用户同时生成条形码时,它们都将获得相同的文件。我正在使用ASP.NET,我正在托管应用程序和内部服务器上的文件。

public void trickylabel(string fnsku, string title)
{
    Random random = new Random();
    int randomNumber = random.Next(0, 100000);

    //Set barcode properties...

    code.parse(fnsku); // Text

    BCGDrawing drawing = new BCGDrawing(this.Server.MapPath("~") + "image"+ randomNumber.ToString() +".png", color_white);
    drawing.setBarcode(code);
    drawing.draw();

    // Draw (or save) the image into PNG format.
    Response.ContentType = "image/png";
    drawing.finish(ImageFormat.Png);

    Document doc = new Document(new iTextSharp.text.Rectangle(200f, 75f), 20F, 10F, 10F, 1F);
    PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(Request.PhysicalApplicationPath +
        "\\"+randomNumber.ToString()+".pdf", FileMode.Create));

    doc.Open();

    iTextSharp.text.Image png = iTextSharp.text.Image.GetInstance(this.Server.MapPath("~") + "image" + randomNumber.ToString() +".png");

    doc.Add(png);

    //Sets pdf properties...

    doc.Add(new Paragraph(title, times));
    PdfAction action = new PdfAction(PdfAction.PRINTDIALOG);
    writer.SetOpenAction(action);
    doc.Close();

    Response.ContentType = "application/pdf";
    Response.AppendHeader("Content-Disposition", "attachment; filename=labels.pdf");
    Response.TransmitFile(Server.MapPath("~/"+randomNumber.ToString()+".pdf"));

}

4 个答案:

答案 0 :(得分:4)

问题在于:

Random random = new Random();
int randomNumber = random.Next(0, 100000);

Random类生成伪随机序列,该序列基于一些起始值,称为Seed。如果用相同的种子初始化两个Random实例,它们将产生相等的数字序列。

使用无参数构造函数创建Random时,将从当前系统时间创建Seed。如果你运行一个创建Random类实例的循环,你会发现random.Next()值每秒只改变几次(每16ms一次)。

为了避免这种情况,你应该重用初始化的Random实例(但是,因为你使用 ASP.Net ,你需要确保在线程安全中执行random.Next()的调用。办法)。然后,您的访问者将获得不同的值,每个新的random.Next(...)调用。

或者,Random有一个构造函数,允许手动设置初始种子值。因此,您可以创建自己的算法,为您的用户创建独特的种子。

UPDATE 线程安全的Randomizer实现。 在程序集加载时初始化。

用法:只需将random.Next(0, 100000);替换为Randomizer.Next(0, 100000);

即可
public static class Randomizer
{
    private static Random rnd;
    static Randomizer()
    {
        rnd = new Random();
        rndlock = new object();
    }

    private static object rndlock;
    public static int Next(int minValue, int maxValue)
    {
        lock(rndlock)
        {
            return rnd.Next(minValue, maxValue);
        }
    }
}

更新关于线程安全和不可预测的结果

如上所述,Random生成伪随机序列。这意味着此序列中的每个int编号都具有已知的上一个和下一个数字。这意味着在一定数量的呼叫之后,这些号码将开始重复。 Random.Next()算法旨在最大化此序列中唯一项的数量。

那么,在这种情况下,“不可预测”是什么意思?当多个线程同时使用相同的变量时,算法的逻辑就会被破坏。在最佳情况下,这使得相同数字的序列更频繁地出现。在最糟糕的情况下,Random.Next()starts to produce zero values on each call没有任何机会恢复。

有关MSDN上的System.Random的更多有用信息。

答案 1 :(得分:1)

或者只使用NewGuid Method

答案 2 :(得分:0)

如果请求同时开始,则生成的随机数可能彼此相同。在没有提供种子值的情况下,Random构造函数根据系统时钟获取其种子,因此两个实例可能产生相同的随机值集合(这些随机值不是随机的,它们是伪随机的)。

此处的文档 - http://msdn.microsoft.com/en-us/library/system.random.aspx

尝试将Random实例设为类的静态成员,并让您的方法只调用该成员上的.Next。

答案 3 :(得分:0)

您需要将pdf保存到磁盘吗?

我建议将png图像和pdf文档保存到MemoryStream。 这也可能会带来更好的性能,因为磁盘访问量更少。

public void trickylabel(string fnsku, string title)
{
    //Set barcode properties...

    code.parse(fnsku); // Text

    BCGDrawing drawing = new BCGDrawing(color_white);
    drawing.setBarcode(code);
    drawing.draw();

    // Draw (or save) the image into PNG format.

    using (var imageStream = new MemoryStream())
    {
        drawing.finish(ImageFormat.Png, imageStream);

        using (var result = new MemoryStream())
        {
            Document doc = new Document(new iTextSharp.text.Rectangle(200f, 75f), 20F, 10F, 10F, 1F);
            PdfWriter writer = PdfWriter.GetInstance(doc, result);

            doc.Open();

            var png = iTextSharp.text.Image.GetInstance(System.Drawing.Image.FromStream(imageStream), ImageFormat.Png);
            doc.Add(png);

            //Sets pdf properties...

            doc.Add(new Paragraph(title, times));
            PdfAction action = new PdfAction(PdfAction.PRINTDIALOG);
            writer.SetOpenAction(action);
            doc.Close();

            Response.ContentType = "application/pdf";
            Response.AppendHeader("Content-Disposition", "attachment; filename=labels.pdf");
            Response.BinaryWrite(result.ToArray());
        }
    }
}