Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Nhibernate检查已用钥匙的最佳方法?_C#_.net_Asp.net Mvc_Nhibernate - Fatal编程技术网

C# 使用Nhibernate检查已用钥匙的最佳方法?

C# 使用Nhibernate检查已用钥匙的最佳方法?,c#,.net,asp.net-mvc,nhibernate,C#,.net,Asp.net Mvc,Nhibernate,在我的网站上,我允许人们批量购买我网站的订阅(我称之为代金券)。一旦他们有了这些凭证,他们就会把它们交给任何人,并将代码输入到他们的帐户中进行升级 现在我正在考虑编写4个字母数字代码(大写、小写和数字),并将有类似的内容 var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; var stringChars = new char[4]; var random = new Random(); fo

在我的网站上,我允许人们批量购买我网站的订阅(我称之为代金券)。一旦他们有了这些凭证,他们就会把它们交给任何人,并将代码输入到他们的帐户中进行升级

现在我正在考虑编写4个字母数字代码(大写、小写和数字),并将有类似的内容

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[4];
var random = new Random();

for (int i = 0; i < stringChars.Length; i++)
{
    stringChars[i] = chars[random.Next(chars.Length)];
}

var finalString = new String(stringChars);
var chars=“abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzo123456789”;
var stringChars=新字符[4];
var random=新的random();
for(int i=0;i
现在,我认为这将给我足够多的组合,如果我用完了,我总是可以增加代码的长度。我想保持简短,因为我不希望用户必须输入大量的数字

我也没有时间做一个更优雅的解决方案,可能是他们点击电子邮件中的链接或其他东西,激活了他们的帐户,当然这会减少人们试图随机猜测凭证号码的次数

如果这个网站越来越受欢迎,我会处理这些事情

我想知道如何处理可能重复生成同一张凭证的问题。我的第一个想法是在每次创建凭证时检查数据库,如果凭证存在,则创建一个新的凭证


然而,这似乎是缓慢的。所以我想也可以先把所有的密钥存储在内存中,然后在内存中进行检查,但是如果列表继续增长,我可能会遇到内存不足的异常和所有这些很棒的东西

有人有什么想法吗?还是我一直在做上面列出的两种方法中的一种

我正在使用nhibernate、asp.net mvc和C

编辑

 static void Main(string[] args)
        {
            List<string> hold = new List<string>();
            for (int i = 0; i < 10000; i++)
            {
                HashAlgorithm sha = new SHA1CryptoServiceProvider();
                byte[] result = sha.ComputeHash(BitConverter.GetBytes(i));
                string hex = null;

                foreach (byte x in result)
                {
                    hex += String.Format("{0:x2}", x);
                }

                hold.Add(hex.Substring(0,3));

                Console.WriteLine(hex.Substring(0, 4));
            }


             Console.WriteLine("Number of Distinct values {0}", hold.Distinct().Count());
        }
static void Main(字符串[]args)
{
列表保持=新列表();
对于(int i=0;i<10000;i++)
{
HashAlgorithm sha=新的SHA1CryptoServiceProvider();
byte[]result=sha.ComputeHash(BitConverter.GetBytes(i));
字符串hex=null;
foreach(结果中的字节x)
{
十六进制+=String.Format(“{0:x2}”,x);
}
hold.Add(十六进制子串(0,3));
控制台写入线(十六进制子字符串(0,4));
}
WriteLine(“不同值的数量{0}”,hold.Distinct().Count());
}
以上是我尝试使用哈希的尝试。然而,我认为我错过了一些东西,因为它似乎有相当多的重复比预期

编辑2

我想我补充了我所缺少的,但不确定这是否正是他的意思。我也不知道当我把它移动到我能移动的地方时该怎么办(我的has似乎给了我40个我能移动的地方)

static void Main(字符串[]args)
{
int subStringLength=4;
列表保持=新列表();
对于(int i=0;i<10000;i++)
{
SHA1CryptoServiceProvider sha=新的SHA1CryptoServiceProvider();
byte[]result=sha.ComputeHash(BitConverter.GetBytes(i));
字符串hex=null;
foreach(结果中的字节x)
{
十六进制+=String.Format(“{0:x2}”,x);
}
int开始位置=0;
字符串possibleVoucherCode=十六进制子字符串(起始位置,子字符串长度);
字符串voucherCode=Move(子字符串长度、保持、十六进制、起始位置、可能的voucherCode);
保留.添加(凭证代码);
}
WriteLine(“不同值的数量{0}”,hold.Distinct().Count());
}
私有静态字符串移动(int subStringLength、列表保持、字符串十六进制、int startingposition、string possibleVoucherCode)
{
if(hold.Contains(可能为Uchercode))
{
int newPosition=startingposition+1;
if(新位置十六进制长度)
{
possibleVoucherCode=十六进制子字符串(newPosition,subStringLength);
返回移动(子字符串长度、保持、十六进制、新位置、可能的触发代码);
}
//归还某物
返回“0”;
}
其他的
{
//归还某物
返回“0”;
}
}
其他的
{
返回可能的用户代码;
}
}
}

您可能的解决方案如下:
查找凭证的最大ID(整数)。然后,对其运行任何哈希函数,取前32位并转换为要向用户显示的字符串(或使用32位哈希函数,如)。这可能会起作用,哈希冲突非常罕见。但是这个解决方案在随机性方面与您的非常相似。


您可以运行一个测试,找到前10个或100个碰撞(这对您来说应该足够了),并强制算法“跳过”它们并使用不同的起始值。然后,您根本不需要检查数据库(至少在您获得大约4294967296张凭证之前……)

使用nHibernate的算法如何?

这是一个关于如何获取下一个值(无需DB访问)的示例。

速度会很慢,因为您希望随机生成凭证,然后检查数据库中生成的每个代码

我将创建一个带有id、代码和is_used列的表
凭单
。我会用足够多的随机代码填满那张表。因为这可以在单独的过程中完成,所以性能不会有太大问题。让它在晚上运行,第二天你会得到一张满桌的凭单

如果您想防止生成重复的凭证,这将不是一个问题
  static void Main(string[] args)
        {
            int subStringLength = 4;
            List<string> hold = new List<string>();
            for (int i = 0; i < 10000; i++)
            {
                SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
                byte[] result = sha.ComputeHash(BitConverter.GetBytes(i));
                string hex = null;

                foreach (byte x in result)
                {
                    hex += String.Format("{0:x2}", x);
                }

                int startingPositon = 0;
                string possibleVoucherCode = hex.Substring(startingPositon,subStringLength);

                string voucherCode = Move(subStringLength, hold, hex, startingPositon, possibleVoucherCode);
                hold.Add(voucherCode);
            }


             Console.WriteLine("Number of Distinct values {0}", hold.Distinct().Count());
        }

    private static string Move(int subStringLength, List<string> hold, string hex, int startingPositon, string possibleVoucherCode)
    {
        if (hold.Contains(possibleVoucherCode))
        {
            int newPosition = startingPositon + 1;
            if (newPosition <= hex.Length)
            {
                if ((newPosition + subStringLength) > hex.Length)
                {
                    possibleVoucherCode = hex.Substring(newPosition, subStringLength);
                    return Move(subStringLength, hold, hex, newPosition, possibleVoucherCode);
                }
                // return something
                return "0";
            }
            else
            {
                // return something
                return "0";
            }
        }
        else
        {
           return possibleVoucherCode;
        }

    }
}
''//given intValue as your random integer
Dim result As String = String.Empty
Dim digits as String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim x As Integer
While (intValue > 0)
   x = intValue Mod digits.Length
   result = digits(x) & result 
   intValue = intValue - x
   intValue = intValue \ digits.Length
End While
Return result
SELECT DISTINCT b.Code
FROM @batch b
WHERE NOT EXISTS (
    SELECT v.Code
    FROM dbo.Voucher v
    WHERE v.Code = b.Code
);
DECLARE @batchid uniqueidentifier;
SET @batchid = NEWID();

INSERT INTO dbo.Voucher (Code, BatchId)
SELECT DISTINCT b.Code, @batchid
FROM @batch b
WHERE NOT EXISTS (
    SELECT Code
    FROM dbo.Voucher v
    WHERE b.Code = v.Code
);

SELECT Code
FROM dbo.Voucher
WHERE BatchId = @batchid;
CREATE TYPE dbo.VoucherCodeList AS TABLE (
    Code nvarchar(8) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL
    /* !!! Remember to specify the collation on your Voucher.Code column too, since you want upper and lower-case codes. */
);
public ICollection<string> GenerateCodes(int numberOfCodes)
{
    var result = new List<string>(numberOfCodes);

    while (result.Count < numberOfCodes)
    {
        var batchSize = Math.Min(_batchSize, numberOfCodes - result.Count);
        var batch = Enumerable.Range(0, batchSize)
            .Select(x => GenerateRandomCode());
        var oldResultCount = result.Count;

        result.AddRange(FilterAndSecureBatch(batch));

        var filteredBatchSize = result.Count - oldResultCount;
        var collisionRatio = ((double)batchSize - filteredBatchSize) / batchSize;

        // Automatically increment length of random codes if collisions begin happening too frequently
        if (collisionRatio > _collisionThreshold)
            CodeLength++;
    }

    return result;
}

private IEnumerable<string> FilterAndSecureBatch(IEnumerable<string> batch)
{
    using (var command = _connection.CreateCommand())
    {
        command.CommandText = _sqlQuery; // the concurrency-safe query listed above

        var metaData = new[] { new SqlMetaData("Code", SqlDbType.NVarChar, 8) };
        var param = command.Parameters.Add("@batch", SqlDbType.Structured);
        param.TypeName = "dbo.VoucherCodeList";
        param.Value = batch.Select(x =>
        {
            var record = new SqlDataRecord(metaData);
            record.SetString(0, x);
            return record;
        });

        using (var reader = command.ExecuteReader())
            while (reader.Read())
                yield return reader.GetString(0);
    }
}