Bob Swart
顾问,Bob Swart Training & Consultancy
2004 年 4 月 本文演示了几种在基于 IBM DB2 UDB 数据库表的 ASP.NET 应用程序中执行数据输入验证的方法。
简介
在这篇文章中,我将演示如何在 IBM® DB2® Universal Database TM(UDB)上构建数据库表和记录的数据输入表单,以及如何使用 Borland® Delphi TM 8 for the Microsoft® .NET Framework(从现在开始缩写为“Delphi 8 for .NET”)和 Borland C#Builder TM 在 ASP.NET Web 表单应用程序中执行数据输入验证。
注意,您将再次使用 Borland Data Provider(BDP)for .NET 连接 DB2 UDB Personal Edition v8.1 数据库,因此,请您确保已阅读先前的文章,它们描述了如何使用 Delphi 8 for .NET或 C#Builder 从 ASP.NET 应用程序来进行连接。本文中的源代码是用 Delphi 编写的,但要将其语法转换成 C# 也不困难。
建立连接
在先前的文章中,我主要使用 ASP.NET DataGrid 组件来展示 DB2 UDB SAMPLE 数据库中 EMPLOYEE 表里多条记录的概貌。在 最新的 Delphi 8 for .NET 文章中,我还展示了特殊的 DB Web 控件。这些控件也可以被 C#Builder 使用,并且这次用来每次显示一条记录,以便终端用户可以插入新数据,或者编辑那些记录的内容。
为了构建本文的示例应用程序,要启动 Delphi 8 for .NET(或 C#Builder),并且创建一个新的 ASP.NET Web 应用程序。将其保存为 DB2DataEntry,因此,用以在您的本地开发机器上测试该应用程序的 URL 将为 http://localhost/DB2DataEntry。
图 1. New ASP.NET Application 对话框
现在,从 Data Explorer中打开 DB2Connection 节点,应将之配置为连接到 IBM DB2 UDB SAMPLE 数据库,并且将 Employee 表拖放至 HTML Designer。这将在 HTML Designer 的非可视区域中创建两个新的组件: BdpConnection1 和 BdpDataAdapter1。
选择 BdpDataAdapter1 组件并单击 Object Inspector底部的 Configure Data Adapter动词。这将启动 Data Adapter Configuration对话框。您不必修改第一个选项卡中的内容,但是需要进入最后一个选项卡( DataSet)中以指定将预先配置的 SELECT 查询的输出放在名为 dataSet1 的新数据集(dataset)中。然后,单击 OK关闭该对话框(关于该对话框的更多细节,请参阅简介中提到的那些文章 —— 它不是这次的主题)。
这样做的结果就是,现在在非可视区域中增加了一个新的组件:dataSet1。将 BdpDataAdapter1 组件的 Active 属性设置为 True,用以确保您在设计时得到实时数据(这非常有助于设计和测试页面,且无需猜测最终的页面样子如何)。
设计 Web 表单
设置了数据集之后,就该构建数据输入表单的可视化部分了。打开 Tool Palette中的 DB Web类别。但是首先要双击 DBWebDataSource 组件,以便同样将之放置在 HTML Designer 的非可视区域中。将 DBWebDataSource 的 DataSource 属性指向为 dataSet1 —— 包含 EMPLOYEE 表上 SELECT 查询结果的 .NET 数据集。DBWeb Data Source 组件将充当可视 DBWeb 控件与 .NET 数据集之间的“网关”。
现在,您可以放入一些 HTML Label 控件(或 Web Controls 类别中的 Label),与一些类似的 DBWebTextBox 控件结合用以生成 DB2 EMPLOYEE 表中的一系列字段。为了设计“绝对”布局的 Web 页面(与流式布局相对),您需要在 Web 表单上拖放所有控件,以使它们保持绝对位置。如果您仅仅双击 Tool Palette中的控件,那么该控件将添加在流式布局中(位于右上角)。
不管怎样,对于每个 DBWebTextBox 控件,都要将其 DBDataSource 属性指向 DBWebDataSource1,它才会与您的 DBWeb Data Source组件进行对话。接下来,您必须将 TableName 属性指向 EMPLOYEE —— .NET 数据集中数据表(DataTable)的名称。最后,您可以将 ColumnName 属性设置为 IBM DB2 UDB SAMPLE数据库中 EMPLOYEE 表里任何可用列的名称,即:EMPNO、FIRSTNME、MIDINIT、LASTNAME、WORKDEPT、PHONENO、HIREDATE、JOB、EDLEVEL、SEX、BIRTHDATE、SALARY、BONUS 或 COMM。
您可以使用 14 个不同的 DBWebTextBox 控件,每个控件都关联 IBM DB2 UDB SAMPLE 数据库中 EMPLOYEE 表里一个不同的字段。
注意,这些控件将显示字段名(在 label 部分)和相应的字段值(在 textbox 部分)。换言之,您可以在设计时看到实时数据,这将有助于您确定每个 DBWebTextBox 控件的宽度。
现在,在 Web 表单上放置一个 DBWebNavigator 控件,并将其 DBWebDataSource 属性指向 DBWebDataSource1 控件,以及将其 TableName 属性指向 EMPLOYEE。现在,ASP.NET Web 表单应该大概如下所示:
图 2. 带有控件和导航器的 IDE 概貌
定位 DBWebNavigator 将允许您在运行时对记录进行定位。现在就保存您的工作,编译该项目并且执行 Run | Run或 Run | Run without Debugging(您仍然无需调试器)来首次运行 ASP.NET Web 项目。
图 3. 执行中的 WebForm
如果这些简单的 Web 表单在浏览器中看上去都正确,那么您可以关闭浏览器并且返回 Delphi 8 for .NET 以向该项目添加数据输入验证的代码了。
验证
您可以向 ASP.NET 项目添加的验证有两种:服务器端验证和客户端验证。如果终端用户在 DBWebTextbox(或 DBWebLabeledTextBox)控件中输入数据并且点击导航器上的下一个按钮,那么这与单击提交按钮是等效的。数据将被发送给 Web 服务器,您现在就可以对终端用户刚刚输入(或修改)的数据执行服务器端的数据验证。如果数据是无效的,您同样可以进行响应。
另一种方法就是当终端用户单击导航器按钮时,执行一小段脚本代码。该脚本代码可以首先尝试检查浏览器中所输入数据的有效性。这称作客户端验证。显然,其好处就是不需要为了验证数据而往返服务器。而其明显的限制就是客户端无法执行所有的验证,这您马上将看到。
使用 ASP.NET 进行验证
使用 ASP.NET,您实际上可以使用验证服务器控件,该控件用以生成客户端脚本。这意味着控件在服务器上运行,但是其脚本却在客户端的浏览器中执行。
ASP.NET 包含六个内置的验证器(validator)控件,即 RequiredFieldValidator、CompareValidator、RangeValidator、RegularExpressionValidator、CustomValidator 和 ValidationSummary。由于它们是 ASP.NET 中的标准控件,所以可以在 Tool Palette 中常规的“Web Controls”类别中找到它们。我不会在这里对它们都进行介绍,但会展示如何将其应用到从数据库(比如 IBM 的 DB2 UDB SAMPLE 数据库)中访问数据的 ASP.NET 项目中。
RequiredFieldValidator
让我们从 RequiredFieldValidator 开始。该控件将强调的事实是:终端用户必须为给定的字段指定一个值。为了说明其使用,请在 ASP.NET Web 表单上从 Web Controls类别中拖出该控件,并放置在您所需要验证(即终端用户必须为其指定一个值)的 DBWebTextBox 旁边。然后,将 RequiredFieldValidator 的 ControlToValidate 属性指向需要进行验证的 DBWebTextBox 控件。就是这样了。
此时,您或许希望对 DBWebTextBox 使用描述性的名称(而不是默认的名称 DBWebTextBox1 到 DBWebTextBox14),比如 DBWTBEmpno、DBWTBFirstnme,等等。
您可以对指向 DB2 UDB SAMPLE 数据库中 EMPLOYEE 表里 EMPNO、FIRSTNME、LASTNAME、HIREDATE、SEX、BIRTHDATE 和 SALARY 等字段的每一个 DBWebTextBox 控件都链接一个 RequiredFieldValidator。这七个字段应该被看作必要字段,而其他七个字段(MIDINIT、WORKDEPT、PHONENO、EDLEVEL、JOB、BONUS 和 COMM)我认为可以为空,所以它们无需链接到 RequiredFieldValidator 控件。
现在,再次编译和运行该应用程序之前,您可能需要再次看一看 RequiredFieldValidator 控件。特别,您应该修改它们的 ErrorMessage 属性值,该属性默认仅为“RequiredFieldValidator”(虽然您可以理解它,但是我不确定您的终端用户会有印象)。您可以输入简单的短语,比如“Field Required”或“Input Required”,或者输入完整的一句话。
除了该错误消息,您可能注意到了 EnableClientScript 属性,它被默认设置为 True。这确保在客户端运行验证。一旦您离开 DBWebTextBox 控件,就会执行该验证。如果 DBWebTextBox 为空,那么将会显示验证的错误消息(以指定的颜色 —— 默认为红色)。
注意,虽然现在在客户端执行该验证(该字段不为空),但是它仍然还是由服务器端的验证控件来执行的。这听起来似乎是多余且不必要的工作,但是由于它可以为重载客户端行为的人们增加多一点的安全性,所以与遗憾相比,我宁愿安全一点 —— 特别是当说到数据输入的验证时。
CompareValidator
另一个 ASP.NET 验证控件就是 CompareValidator。RequiredFieldValidator 只能验证一个字段是否为空,而 CompareValidator 可以将一个字段的内容与一个值或数据类型进行比较。当涉及到 Web 输入时,后者极其方便,因为在将货币或其他数字输入字段的值发送给服务器之前,您需要对它们进行验证。CompareValidator 具有两个属性让您用以验证 DBWebTextBox:ControlToCompare 或 ControlToValidate。第一个将该字段值与一个给定值进行比较;第二个将字段内容与给定类型进行比较。现在,您将使用第二个。您可以通过将类型设置为 Integer(该电话号码只包含数字)以及将 Operator 属性设置为 DateTypeCheck,使用 CompareValidator 来验证 PHONENO 字段的输入类型。您还可以通过将类型设置为 Currency 以及再次将 Operator 设置为 DateTypeCheck,使用 CompareValidator 来验证 SALARY、BONUS 和 COMM 字段的输入类型。注意,Currency 类型将强制在小数点后只能使用零个、一个或两个数字,不能再多加数字,而 Double 类型允许小数点后有任意多个数字。
注意,您已经将一个 RequiredFieldValidator 连接到了 SALARY 字段。因为这两个控件之中只能激活一个(该字段可以是正确的,或者为空,或者不是所要求的货币类型),所以您可以将两个不同的验证器控件放置在彼此的上面!
除了用 CompareValidator 验证该输入是否为特定的类型,您还可以使用 CompareValidator 来将一个字段值与一个指定值通过 operator Equal、NotEqual、GreaterThan、GreaterThanEqual、LessThan 或 LessThanEqual 操作符进行比较。
RangeValidator
到目前为止,您已经能够检查一个字段是否为空,以及一个字段是否包含指定类型中的值(或匹配一个特定值)。使用 RangeValidator,您可以更进一步,并且检查一个字段值是否在一个指定的范围之内。例如,您可以验证奖金或佣金不为负数或高出指定的最大值,或者验证教育水平至少为某值。为了构建这些示例,要将 RangeValidator 控件放置在 DBWTBEDLEVEL 控件旁边,并将 ControlToValidate 属性设置为 DBWTBLEVEL、类型设置为 Integer、 MinValue 设置为 12 以及 MaxValue 设置为 24。确保要设置 ErrorMessage 属性,例如设为“Education level must be between 12 and 24”。
另一个 RangeValidator 可用于两个日期字段:BIRTHDATE 和 HIREDATE。显然,某人应该至少有一个固定年龄,并且某人在他或她出生之前都不可能被雇佣。通过将一个 RangeValidator 控件放置在 DBWTBBIRTHDATE 字段旁边,将 ControlToValidate 连接到 DBWTBBIRTHDATE,将类型设置为 Date,将 MinValue 设置为 1935-01-01(假设没有人超过 69 岁才开始为我们工作),以及将 MaxValue 设置为 1990-01-01(假设没有人不满 14 岁就开始为我们工作),可以实现第一条验证规则。同样的值可以用于连接到 DBWTBHIREDATE 的 RangeValidator 控件中。在这两个实例中,您都应该设置 ErrorMessage 属性以确保当数据超出指定范围时,显示一条可判断的错误消息。
RegularExpressionValidator
另一个我在这里不将演示的验证器控件就是 RegularExpressionValidator。该验证器控件的工作方式与 CompareValidator 或 RangeValidator 一样,但它使用正则表达来验证输入字段的值。这可用于复杂的值,例如邮政分区或邮政编码。
CustomValidator
另一个我将略微详细演示的验证器控件就是 CustomValidator。该控件可用于为客户端或服务器端指定您自己定制的验证脚本代码。由于您已经看到了一些客户端验证示例,所以就让我用它来实现某种服务器端的验证。将 ControlToValidate 属性指向 DBWTBWORKDEPT,然后进入 Object Inspector的 events 选项卡并且实现 ServerValidate 事件处理程序以验证 WORKDEPT 字符串(例如,通过检查它是否以字母开头并且紧接一个整数),如下:
procedure TWebForm1.CustomValidator1_ServerValidate(source: System.Object;
args: System.Web.UI.WebControls.ServerValidateEventArgs);
var
Str: String;
begin
Str := args.Value;
if (Str[1] in ['A'..'Z'])
and (StrToIntDef(Copy(Str,2,255),-1) >= 0)
then
args.IsValid := True
else
args.IsValid := False // invalid
end;
|
当您重新回到 DBWebNavigator 时,立刻就要重新调用服务器端验证。但是首先要结束最后一个验证控件。
ValidationSummary
ValidationSummary 控件是一个特殊的验证控件。实际上,它不是一个真正的验证控件,更多的是在一个页面中罗列所有验证违规摘要的控件。您可以将之放置在 Web 表单上,它将自动显示可多次使用的(项目)列表中的所有错误。
摘要可以在 ValidationSummary 控件本身中显示,或使用一个基于 ValidationSummary 控件的 ShowSummary 属性值的消息框(messagebox)。
DBWebNavigator
注意,只要一条客户端验证约束失败,就不可能使用导航器移到另一条记录,这时只能单击 Apply Updates 按钮或单击 Undo 按钮。终端用户在他/她真正可以单击导航器之前,首先必须解决所有的本地字段验证违规。而后,您才可以执行服务器端的验证规则。Web 页面变量“Page”有一个称作 IsValid 的方法将推行一系列的服务器端验证规则,以确定该页面是否有效。如果无效,那您可以输出错误消息(注意,将使得 CustomValidator 可见)。
使用 DBWebNavigator,您还应该确保在更正不正确的输入字段值之前,无法滚到另一条记录。这可以在 DBWebDataSource 组件的 OnScroll 事件中完成,如下:
procedure TWebForm1.DBWebDataSource1_OnScroll(sender: System.Object;
e: Borland.Data.Web.OnScrollEventArgs);
begin
if not Page.IsValid
then // scroll back
(DBWebDataSource1 as IDBPostStateManager).
SetCurrentRow(Page, e.TableName, e.PriorRow)
end;
|
该代码将确保维持当前记录,以便终端用户可以解决问题。
OnApplyChangesRequest
从上次开始,您就知道为了将更新发回给底层的 DB2 DBMS,您必须实现 DBWebDataSource 的 OnApplyChangesRequest 方法。除了将更新发送给 DB2 UDB SAMPLE 数据库,然而这也是最后一个可以检查更新有效性的机会。因此,您可以在这里编写一些代码来验证输入,并且至少要调用 Page.IsValid 方法来确定是否遗漏了验证问题:
procedure TWebForm1.DBWebDataSource1_OnApplyChangesRequest(sender: System.Object;
e: Borland.Data.Web.WebControlEventArgs);
begin
if Page.IsValid
then
BdpDataAdapter1.AutoUpdate
end;
|
下面显示了设计时 ASP.NET Web 页面的最终式样。注意,有些验证器被放在彼此的上面(比如 SALARY 字段的 RequiredFieldValidator 和 CompareValidator),但是不管怎样,只会显示一个。
图 4. 带有控件和导航器的 IDE 概貌
下面的屏幕快照显示了 Web 浏览器中正在执行的 ASP.NET Web 应用程序,其中违反了一些验证规则,所以在解决所有错误消息之前,您无法继续查看另一条记录。
图 5. 带有验证器的执行中的 WebForm
结束语
本文中,我演示了几种在基于 IBM DB2 UDB 数据库表的 ASP.NET 应用程序中执行数据输入验证的方法。最有效的方法就是使用通过将 ASP.NET 验证控件与 Borland DBWeb 控件结合的客户端字段-值验证。您已经查看了 RequiredFieldValidator、CompareValidator、RangeValidator、RegularExpressionValidator、CustomValidator 和 ValidationSummary。您还看到了如何应用服务器端验证,以及如何确保 DBWeb 控件在解决所有的验证问题之前,阻止将更新送回服务器。
使用数据输入验证规则将使您能够用 C#Builder 或 Delphi 8 for .NET 编写更健壮的 Web 应用程序来处理 IBM DB2 UDB 数据库表。
关于作者
Bob Swart(也称为 Bob 博士—— www.drbob42.com)在他自己的公司 Bob Swart Training & Consultancy (eBob42)(位于荷兰 Helmond)的身份是作家、教员、顾问和 Web 管理员。Bob 编写了自己的 Delphi 培训教材,并且从 1993 年以来一直在 Delphi 和 Borland 开发者大会上发表演讲。Bob 已经撰写了数百篇文章,并且与别人合著了 Revolutionary Guide to Delphi 2、 Delphi 4 Unleashed、 C++Builder 4 Unleashed、 C++Builder 5 Developer's Guide、 Kylix Developer's Guide、 Delphi 6 Developer's Guide 和 C++Builder 6 Developer's Guide。 |
|