ASP.NET的信用卡验证器控件

分享于 

22分钟阅读

Web开发

  繁體

样例图像

介绍

一段时间之前,我开始使用他们的XML API将电子商务支付( 网关 DataCash ) 服务器转换为本机. NET 程序集。 有了基本版本工作之后,我决定生成一个简单的web表单来测试它,所以打开了所有的vi (。感谢--成员提供的一些非常慷慨的捐赠:)。 我想包括支持,检查用户是否输入了卡号。过期日期 等等,然后将它的扩展到支持支付服务器。 结果是,任何其他验证控件的替换都会丢失。

另外,你可以看到在以下地址使用( 以及卡支付网关程序集)的验证程序的演示: 除了这个你可能还对你想知道的关于cc指南的内容感兴趣的东西。

在进入任何实现细节之前,都有一个简单的UML类图来显示控件的大致布局。

图表缺少有关参数类型的信息,因为它对于理解模型不重要。 对于那些不熟悉UML的人,它显示 BaseValidatorCreditCardValidator 类之间的专门化关系- 一个关系- 从 BaseValidator 向更加特殊的CreditCardValidator 类展示继承。 of的第三个代码是 AcceptedCardTypes 属性,用于指定用 CardType 枚举传递验证的类型。

控件包括通过两种方式验证卡编号的支持。 首先,通过使用luhn公式检查卡号,在文章的下一部分中包括它的详细信息。 其次,检查卡类型本身,并检查它的长度。 可以通过前缀确定卡类型,并且每种类型都具有指定的长度。 实现这里方法的方法是 IsValidCardType,它是否在验证期间使用,由 ValidateCardType 属性设置。

通过luhn公式验证卡号的主要方式是通过公式,以及如何执行验证。

luhn公式

CreditCardValidator 控件将使用luhn的公式对文本框内容执行检查,这些公式用于验证卡号。 它可以用于检查多个卡,包括:

  • 万事达卡
  • VISA
  • 美国运通信用卡
  • Diners俱乐部/贵宾贵宾
  • 航路
  • 发现
  • JCB
  • Solo*
  • Switch*

* 这些是英国唯一的记忆卡,但是已经被我自己和工作测试过了。

可以在找到关于公式的历史信息,但是你不必阅读这里是的摘要,它是如何执行的。

  • 交替位数的两倍两倍
    第一步是把数字中每一个交替的数字加倍。 但诀窍是从右边的第二个数字开始,然后反向工作。 假设我们有一个信用卡号码 1234 5678 1234. 我们从最右边的数字 7开始,加倍它,然后对其他数字做同样的操作。

1234 5678 1234 5670

这将给我们以下值。

7 x 2 = 14
5 x 2 = 10
3 x 2 = 6


等等.

给所有产品加上单独的数字
我们将把所有产品的数字分开,并得到最终的总和。

( + 4 + ( 1 + 0 ) + 6 + + ( 1 + 4 ) + + 6 + 2 = 28

一定要加上数字,而不仅仅是数字。

  • 添加不受影响的数字
    现在我们回到原来的数字,并添加我们没有加倍的所有数字。 我们还是从右边开始,但这次我们从最右边的那个开始。

1234 5678 1234 5670
0 + 6 + 4 + 2 + 8 + 6 + 4 + 2 =

添加结果并除以 10
最后,我们将同时添加结果并将答案划分为0.

28 + 32 = 60

60均匀除以 10,所以信用卡号码形成,并准备进一步处理。

这将转换为一个方法,该方法将执行指定文本框的内容上列出的所有步骤。 通过从 BaseValidator 派生新的验证器控件,可以生成一个控件,它的行为与最简单部署的任何它的他验证器。

luhn的实现

luhn公式的代码位于 ValidateCardNumber 方法中,该方法的实现如下:

privatestaticbool ValidateCardNumber( string cardNumber )
{
 try 
 {
 // Array to contain individual numbers System.Collections.ArrayList CheckNumbers = new ArrayList();
 // So, get length of cardint CardLength = cardNumber.Length;
 // Double the value of alternate digits, starting with the second digit// from the right, i.e. back to front.// Loop through starting at the endfor (int i = CardLength-2; i >= 0; i = i - 2)
 {
 // Now read the contents at each index, this// can then be stored as an array of integers// Double the number returned CheckNumbers.Add( Int32.Parse(cardNumber[i].ToString())*2 );
 }
 int CheckSum = 0; // Will hold the total sum of all checksum digits// Second stage, add separate digits of all productsfor (int iCount = 0; iCount <= CheckNumbers.Count-1; iCount++)
 {
 int _count = 0; // will hold the sum of the digits// determine if current number has more than one digitif ((int)CheckNumbers[iCount] >9)
 {
 int _numLength = ((int)CheckNumbers[iCount]).ToString().Length;
 // add count to each digitfor (int x = 0; x < _numLength; x++)
 {
 _count = _count + Int32.Parse( 
 ((int)CheckNumbers[iCount]).ToString()[x].ToString() );
 }
 }
 else {
 // single digit, just add it by itself _count = (int)CheckNumbers[iCount]; 
 }
 CheckSum = CheckSum + _count; // add sum to the total sum }
 // Stage 3, add the unaffected digits// Add all the digits that we didn't double still starting from the// right but this time we'll start from the rightmost number with // alternating digitsint OriginalSum = 0;
 for (int y = CardLength-1; y >= 0; y = y - 2)
 {
 OriginalSum = OriginalSum + Int32.Parse(cardNumber[y].ToString());
 }
 // Perform the final calculation, if the sum Mod 10 results in 0 then// it's valid, otherwise its false.return (((OriginalSum+CheckSum)%10)==0);
 }
 catch {
 returnfalse;
 }
}

代码包含解释它如何工作的注释,但是这里有一个总结。

  • 构建一个 ArrayList,其中包含步骤 1中的交替数字。 这样就可以在步骤 2中再次使用原始值,但不需要通过。 这主要是为了提高可读性。
  • 创建列表后,如果数字大于 9 ( 例如 ),则会创建一个单独的数字。 有多个数字)。
  • 未被修改的原始数字将被添加到一起,这将创建 OriginalSum 变量。 然后将这个值添加到第 1步和第 2步创建的数字,并将值除以 10,并根据 0测试结果,从而为函数的返回值进行测试。

如果在整个代码中抛出异常,则返回 false。

卡类型验证

可以根据数字前缀对上面提到的每个卡类型进行测试,以获得给定的长度。 前缀和长度位于下面的表格中:

卡类型前缀
万事达卡51-5516
VISA413或者 16
美国运通信用卡34或者 3715
Diners俱乐部/贵宾贵宾300-305,36,3814
航路2014,214915
发现601116
JCB316
JCB2131,180015

可以将这些类型放入枚举中。 这将允许我们包括一个属性,用户可以设置指定接受哪些类型,然后测试属性。

[Flags, Serializable]publicenum CardType
{
 MasterCard = 0x0001,
 VISA = 0x0002,
 Amex = 0x0004,
 DinersClub = 0x0008,
 enRoute = 0x0010,
 Discover = 0x0020,
 JCB = 0x0040,
 Unknown = 0x0080,
 All = CardType.Amex | CardType.DinersClub |
 CardType.Discover | CardType.Discover |
 CardType.enRoute | CardType.JCB |
 CardType.MasterCard | CardType.VISA
}

CardType ( 它是Int32-based枚举类型的实例) 将用作一组位标志- 每个位反映一个卡类型。 0.。0001是万事达卡 0.。0010是 VISA。 通过使用一组位标志,可以将一个变量设置为多个卡类型,并能够确定哪些是支持的。

这张卡类型检查将在长度检查( 确保卡号与类型长度所期望的卡匹配) 和这里检查,我们将使用正则表达式使用. NET 正规表达式 框架类。 正规表达式 允许你执行 Pattern 匹配,并且可以非常强大。 更多关于 正规表达式的详细信息,请查看 MSDN. NET 框架 正规表达式,如果你只想包含这种验证,你可以使用正则表达式验证控件。

卡类型检查还包括对最终用户指定哪些卡类型应该通过验证的支持,这是通过 AcceptedCardTypes 属性( 然后存储在 _cardTypes 成员变量中) 设置的。 代码如下所示:

publicbool IsValidCardType( string cardNumber )
 { 
 // AMEX -- 34 or 37 -- 15 lengthif ( (Regex.IsMatch(cardNumber,"^(34|37)")) 
 && ((_cardTypes & CardType.Amex)!=0) )
 return (15==cardNumber.Length);
 // MasterCard -- 51 through 55 -- 16 lengthelseif ( (Regex.IsMatch(cardNumber,"^(51|52|53|54|55)")) && 
 ((_cardTypes & CardType.MasterCard)!=0) )
 return (16==cardNumber.Length);
 // VISA -- 4 -- 13 and 16 lengthelseif ( (Regex.IsMatch(cardNumber,"^(4)")) && 
 ((_cardTypes & CardType.VISA)!=0) )
 return (13==cardNumber.Length||16==cardNumber.Length);
 // Diners Club -- 300-305, 36 or 38 -- 14 lengthelseif ( (Regex.IsMatch(cardNumber,"^(300|301|302|303|304|305|36|38)")) && 
 ((_cardTypes & CardType.DinersClub)!=0) )
 return (14==cardNumber.Length);
 // enRoute -- 2014,2149 -- 15 lengthelseif ( (Regex.IsMatch(cardNumber,"^(2014|2149)")) && 
 ((_cardTypes & CardType.DinersClub)!=0) )
 return (15==cardNumber.Length);
 // Discover -- 6011 -- 16 lengthelseif ( (Regex.IsMatch(cardNumber,"^(6011)")) &&
 ((_cardTypes & CardType.Discover)!=0) )
 return (16==cardNumber.Length);
 // JCB -- 3 -- 16 lengthelseif ( (Regex.IsMatch(cardNumber,"^(3)")) && 
 ((_cardTypes & CardType.JCB)!=0) )
 return (16==cardNumber.Length);
 // JCB -- 2131, 1800 -- 15 lengthelseif ( (Regex.IsMatch(cardNumber,"^(2131|1800)")) && 
 ((_cardTypes & CardType.JCB)!=0) )
 return (15==cardNumber.Length);
 else {
 // Card type wasn't recognised, provided Unknown is in the // CardTypes property, then return true, otherwise return false.if ( (_cardTypes & CardType.Unknown)!=0 )
 returntrue;
 elsereturnfalse;
 }
}

它不是最漂亮的代码,但是它有效地对每个可能的卡类型执行 cardNumber的正规表达式 比较。 正则表达式非常简单,并且搜索由管道字符分隔的任意数字。 因此,对于美国运通,它搜索 34或者 37. 因为字符串是由点( ^ ) 字符前缀的,所以在 cardNumber的开始处执行搜索。 这里搜索是通过 Regex 类的IsMatch static 方法执行的。

同时还进行了一次测试,以确定 AcceptedCardTypes 属性中是否存在卡类型:

&& ((_cardTypes & CardType.Amex)!=0)

同时提供了测试 return true ( 例如。 前缀已经匹配,并且在 _cardTypes 成员变量中存在卡类型),并且提供卡号,然后 IsValidCardType 方法为 return true。

如果卡类型无法识别,那么只要 Unknown 已经在 _cardTypes 中设置,IsValidCardType 将 return true - 因为用户将指定 Unknown 卡类型是接受的卡类型。 否则,它将会是 return false 并且会失败。

使用如下所示的属性访问器设置 _cardTypes 变量:

publicstring AcceptedCardTypes
{
 get {
 return _cardTypes.ToString();
 }
 set {
 _cardTypes = (Etier.CardType)
 Enum.Parse(typeof(Etier.CardType), value, false );
 }
}

这样用户就可以使用字符串指定卡片类型( 比如。 ",VISA,未知"),与必须通过编程方式设置它相反。 OnLoad事件( 比如。 AcceptedCardTypes = CardType.VISA | CardType.Amex 等等 )

所实现的第二个验证方法是生成使用上述方法来验证关联控件中的文本的BaseValidator 派生类。

控件的验证实现

这是编写的大部分代码,剩下的就是生成一个dervied类 System.Web.UI.WebControls.BaseValidator 并重写必要的功能。 另外,我使用civici的Cenk文章作为"listcontrol开发者"的主要来源,这是。

如果关联文本框中输入了有效的信用卡号,那么 BaseValidator 要求我们重写 EvaluateIsValid 方法,该方法的suprisingly是确定关联控件是否具有有效的内容--的函数。 我还包含了的文章,它还包含了 ControlPropertiesValid helper 函数的实现,它决定了 ControlToValidate 属性指定的控件是否是一个有效的控件,从而确保它是我们检查。 由于大多数控件都有一个文本属性,但是很奇怪,确认按钮 等等的文本属性。

首先,knol

protectedoverridebool ControlPropertiesValid()
{
 // Should have a text box control to check Control ctrl = FindControl(ControlToValidate);
 if ( null!= ctrl )
 {
 if (ctrl is System.Web.UI.WebControls.TextBox)
 {
 _creditCardTextBox = (System.Web.UI.WebControls.TextBox) ctrl;
 return ( null!= _creditCardTextBox );
 } elsereturnfalse;
 }
 elsereturnfalse;
}

代码首先找到 ControlToValidate 并检查它确实指向什么,然后检查它是否是 TextBox。 如果是,它将成员变量 _creditCardTextBox 设置为web窗体上的TextBox。 如果发生任何错误,它返回 false

最后,EvaluateIsValid

这里方法在 BaseValidator 类中声明为抽象方法,因此必须由我们的派生类实现。 同时调用该方法来检查关联控件的内容是否有效。

CreditCardValidator 控件包含两个附加属性,其中一个是 ValidateCardType,可以用于设置是否也检查卡类型。 如果要检查,则在对luhn的公式进行数值评估之前检查长度。 但是,如果 ValidateCardType 属性设置为 false,则直接根据luhn的公式验证卡号。

protectedoverridebool EvaluateIsValid()
{
 if (_validateCardType) // should the length be validated also? {
 // Check the length, if the length is fine then validate the// card numberif (IsValidCardType(_creditCardTextBox.Text))
 return ValidateCardNumber( _creditCardTextBox.Text );
 elsereturnfalse; // Invalid length }
 else// Check that the text box contains a valid number using // the ValidateCardNumber methodreturn ValidateCardNumber( _creditCardTextBox.Text );
}

如果 ValidateCardNumber 方法成功,则验证被认为是成功的。

使用信用卡验证程序控件

这就是 CreditCardValidator 控件完成所必需的全部。 关于如何在( 这里代码的完整代码作为下载内容包含在页面顶部) 中使用它的快速示例的示例。

首先需要将声明包括在aspx页的顶部,导入程序集并将该命名空间映射到前缀。 这也要求将程序集文件的DLL复制到应用程序的bin目录中。 这个目录的位置取决于应用程序的设置,但是假设 root called/CreditCard/then 中有一个虚拟目录,你的bin目录将会显示一个目录。

<%@RegisterTagPrefix="etier"Namespace="Etier"Assembly="CreditCardValidator"%>

这样就可以将控件以 <etier:CreditCardValidator的形式添加到页中。 例如下面的代码将验证器控件绑定到名为 cardNumberTextBox:

<etier:CreditCardValidator
 Id="MyValidator" ControlToValidate="CardNumber" ErrorMessage="Please enter a valid credit card number" Display="none" RunAt="server" EnableClientScript="False" ValidateCardType="True" AcceptedCardTypes="Amex, VISA, MasterCard"/>

CreditCardValidator 提供了一些不从 BaseValidator 基类型获取的属性,这些属性是 ValidateCardTypeAcceptedCardTypesValidateCardType 属性设置是否应检查卡类型。 这意味着执行长度测试,以及指定应该接受哪些卡类型。 可以使用CardType枚举来设置AcceptedCardTypes属性。 在上述代码中,接受的类型是 Amex。VISA和 MasterCard。 如果无法识别的卡类型也被接受,那么你可以在列表中包含"未知"。 如果你想接受所有认可的类型,那么你可以使用"全部"。 因此,要接受任何你应该使用"未知,全部"。

由于选择将错误消息显示在 ValidationSummary 控件中,我将 Display 属性设置为 none,以确保它不会在控件中显示。 否则,错误消息将放置在这里控件的位置。

结束语

ASP.NET 提供了大量的功能,我不能记住我生成了多少次自定义代码来执行验证控制。 这种结合了面向对象的特性,意味着你可以将现有的产品扩展到可以使用的时间和时间。 现在of是web应用程序的真正选项,可以在一段时间内完成对自定义验证控件的支持。

这是我的第二篇文章,我希望它对人们有帮助。 它并没有真正显示任何新的功能,但是可以将一些重要的功能转换为可以部署和使用的控件。

缺少的东西/改进的想法

目前,所有验证都是在服务器端处理的。 因为目的是防止发送到付款网关的请求具有不正确的细节- 特别是因为有几秒钟。 然而,由于验证算法不是秘密,而且实现相对简单,可以实现客户端版本检查数据。

如果有人决定扩展它以包括客户端脚本,或者有任何注释或者问题,那么就很好了。

历史记录

  • 更新:24/08/2002 我增加了对指定控件应该接受的卡类型的支持。 对 IsValidLength 方法的实现进行了更改,该方法已经被重命名为 IsValidCardType。 可以使用 AcceptedCardTypes 属性设置要接受的卡类型,该属性使用 CardType 枚举。
  • 更新:21/08/2002 shortly发布第一个版本后不久,我包括了验证数字的长度的支持。 下面的文章显示了新的更新版本。

控制  asp  asp-net  CAR  validator  信用卡  
相关文章