ASP.NET 使用 Ajax 进行验证






4.16/5 (9投票s)
本文介绍如何使用 Ajax 进行服务器端验证。
引言
很多时候,在将页面提交到 Web 服务器之前执行 JavaScript 验证是可取的。对于简单的验证,客户端 JavaScript 验证就足够了。然而,在复杂的情况下,可能需要进行服务器端验证,而客户端 JavaScript 无法满足。在这些情况下,通常必须执行回发(postback)才能进行服务器端验证。在许多情况下,开发人员可能不希望因为验证而导致页面回发,因为这可能会丢失页面状态,并且用户体验也不是最流畅的。这时 Ajax 就派上用场了。本文利用 Ajax 的强大功能,通过 JavaScript 在不依赖回发的情况下执行服务器端验证。
背景
如前所述,本文提出的主要思想是在出现复杂情况时,如何避免回发而执行服务器端验证。下面的控件可以用作集中的验证组件,可以执行 ASP.NET 网站的所有验证。
Ajax 示例
在详细介绍验证工作原理之前,我们将演示如何进行简单的 Ajax 调用。有关 Ajax 的更多信息,请参阅 ASP.NET 的 Ajax 技术和框架入门。
在我们的示例中,我们将使用 Michael Schwartz 开发的 Ajax.NET 组件。我们选择此组件是因为它非常易于实现,并且提供了极大的灵活性。
为了成功使用 Ajax.NET 组件,需要在 web.config 中应用以下设置。有关这些设置的详细解释,请参阅 Michael Schwartz 的网站 Ajax.NET。
<configSections>
<sectionGroup name="ajaxNet">
<!-- If you are using Microsoft .NET 1.1 please remove the two attributes
<!-- requirePermission and restartOnExternalChanges, they
<!-- are only supported with .NET 2.0.-->
<section name="ajaxSettings"
type="AjaxPro.AjaxSettingsSectionHandler,AjaxPro.2"
requirePermission="false" restartOnExternalChanges="true"/>
</sectionGroup>
</configSections>
<ajaxNet>
<ajaxSettings>
<urlNamespaceMappings useAssemblyQualifiedName="false">
</urlNamespaceMappings>
<jsonConverters></jsonConverters>
<debug enabled="false" />
<token enabled="false" sitePassword="password" />
<oldStyle>
<includeMsPrototype/>
</oldStyle>
</ajaxSettings>
</ajaxNet>
<location path="ajaxpro">
<system.web>
<httpHandlers>
<add verb="*" path="*.ashx"
type="AjaxPro.AjaxHandlerFactory,AjaxPro.2"/>
</httpHandlers>
</system.web>
</location>
进行简单的 Ajax 调用
创建一个简单的网页,其中包含一个 HTML 文本框和一个按钮控件。请注意,按钮的 onclick
事件调用 JavaScript 函数 makeAjaxCall()
,该函数调用后台代码中的 Ajaxsample.AjaxTest
Ajax 方法。
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Ajax.NET Sample</title>
<script>
function makeAjaxCall()
{
var retVal = AjaxSample.AjaxTest(document.form1.txtTest.value)
alert(retVal.value)
}
</script>
</head>
<body>
<form id="form1" runat="server">
<!--Client Side text -->
Enter value:<input type="text" id="txtTest"/>
<!--<span class="code-comment">Client Side button -->
<input type="button" id="btnTest" value="Test Ajax"
onclick="makeAjaxCall()" />
</form>
</body>
</html></span>
后台类应标记为 <AjaxPro.AjaxNamespace("AjaxSample")>
,并且要调用的 Ajax Web 方法应标记为 <AjaxPro.AjaxMethod()>
。此外,页面加载事件应使用 AjaxPro.Utility.RegisterTypeForAjax(GetType(AjaxSample), Page)
注册 AjaxSample
命名空间。以下是显示后台代码的代码片段。
<AjaxPro.AjaxNamespace("AjaxSample")> Partial Public Class AjaxSample
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
AjaxPro.Utility.RegisterTypeForAjax(GetType(AjaxSample), Page)
End Sub
<AjaxPro.AjaxMethod()>
Public Function AjaxTest(ByVal testParam As String) As String
Return "You sent '" & testParam & "' as the testParam."
End Function
End Class
以下是创建的示例页面的输出。
构建验证控件
我们创建一个 Web 用户控件,以便该控件可以在应用程序的所有 Web 页面之间重用。此控件将支持的验证定义在 Enum ValidationType
中。可以扩展它以支持未涵盖的附加验证。
Public Enum ValidationType
RequiredField = 1
DateRangeValidation = 4
SingleDateValidation = 2
CreditCardNumberValidation = 3
DropdownlistValidation = 5
DropdownlistRangeValidation = 11
EmailValidation = 7
PostalCodeValidation = 8
URLValidation = 9
TimeSlotRangeValidation = 10
Numeric = 12
HoursValidation = 13
MinutesValidation = 14
CompareValidation = 15
TimeSlotValidation = 16
End Enum
将控件类标记为 <AjaxPro.AjaxNamespace("AjaxValidator")>
,方法标记为 <AjaxPro.AjaxMethod()>
,最后在页面加载事件中使用 AjaxPro.Utility.RegisterTypeForAjax(GetType(Validator), Page)
注册命名空间,其中 Validator
是用户控件的类名。这与我们在早期示例中所做的类似。
创建一个结构 RegisteredControlsDs
和一个列表类(list class)的 private
成员,用于包含要验证的 RegisteredControlsDs
类型的 Web 控件列表。
Private Structure RegisteredControlsDs
Public control1 As UI.Control
Public control1Desc As String
Public control2 As UI.Control
Public control2Desc As String
Public type As ValidationType
Public isRequired As Boolean
Public Sub New(ByVal control1 As UI.Control,
ByVal control1Desc As String,
ByVal control2 As UI.Control,
ByVal control2Desc As String,
ByVal type As ValidationType,
ByVal isRequired As Boolean)
Me.control1 = control1
Me.control1Desc = control1Desc
Me.control2 = control2
Me.control2Desc = control2Desc
Me.type = type
Me.isRequired = isRequired
End Sub
Public Sub New(ByVal control1 As UI.Control,
ByVal control1Desc As String,
ByVal type As ValidationType,
ByVal isRequired As Boolean)
Me.control1 = control1
Me.control1Desc = control1Desc
Me.control2 = control1
Me.control2Desc = control1Desc
Me.type = type
Me.isRequired = isRequired
End Sub
End Structure
Private _registeredControlsList As New List(Of
RegisteredControlsDs)
要验证的控件应添加到 _registeredControlsList
列表中。根据验证是在单个控件上进行还是在两个控件之间进行,使用以下两种方法之一分别注册控件。例如,如果是两个控件之间的比较,则使用第二种方法。如果是一个需要为 Date
等进行验证的单个控件,则使用第一种方法注册控件。
//Method 1
Public Sub RegisterControl(ByVal control As UI.Control, _
ByVal controlDesc As String, _
ByVal type As ValidationType, _
ByVal isRequired As Boolean)
_registeredControlsList _
.Add(New RegisteredControlsDs(control, controlDesc, type, isRequired))
End Sub
//Method 2
Public Sub RegisterControls(ByVal control1 As UI.Control, _
ByVal control1Desc As String, _
ByVal control2 As UI.Control, _
ByVal control2Desc As String, _
ByVal type As ValidationType, _
ByVal isRequired As Boolean)
_registeredControlsList_
.Add(New RegisteredControlsDs(control1, control1Desc,_
control2, control2Desc, type, isRequired))
End Sub
使用上述方法注册控件后,下一步是创建一个 ValidateControls
方法来验证控件。根据是单个控件验证还是两个控件之间的验证,ValidateControls
调用一个重载的 ValidateControl
方法。这些方法返回一个 ValidationResult
数据结构。
''' <summary>
''' This is the Ajax Method which is used to validate a set of UI
''' Controls.
''' </summary>
<AjaxPro.AjaxMethod()>
Public Function ValidateControls(ByVal ds As DataSet) As ValidationResult
Dim retVal As New ValidationResult(True)
Try
Dim dt As DataTable = ds.Tables(0)
Dim firstBadControl As String = String.Empty
For Each dr As DataRow In dt.Rows
Dim val1Name As String = dr("Control1Name")
.ToString()
Dim val1 As String = dr("Control1Value").ToString()
Dim val1Desc As String = dr("Control1Description")
.ToString()
Dim val2Name As String = dr("Control2Name")
.ToString()
Dim val2 As String = dr("Control2Value").ToString()
Dim val2Desc As String = dr("Control2Description")
.ToString()
Dim isreq As Boolean = Boolean.Parse(dr(
"IsRequired").ToString)
Dim type As ValidationType = CType(dr(
"ValidationType"), ValidationType)
Dim validationResult As ValidationResult
If val1Name = val2Name Then
validationResult = ValidateControl(val1Name,
val1Desc, val1, isreq, type)
Else
validationResult = ValidateControl(val1Name,
val1Desc, val1, val2Name,
val2Desc, val2, isreq, type)
End If
If Not validationResult.Status Then
retVal.Message &= validationResult
.Message & Environment.NewLine
retVal.Status = False
If firstBadControl = String.Empty Then
firstBadControl = val1Name
End If
Next
retVal.InvalidControlName = firstBadControl
Catch ex As Exception
retVal.Message = "Ajax Exception:" & ex.ToString()
retVal.Status = False
End Try
Return retVal
End Function
最后,RegisterScript
方法根据服务器端已注册的控件动态生成 JavaScript。
''' <summary>
''' Registers the Validation Script.
''' Javascript is generated based on which controls have been registered,
''' along with the Ajax call.
''' </summary>
Public Sub RegisterScript()
Dim scriptCode As String = _
"<script language="'javascript'" type='text/javascript'>" & _
"function _validatePage()" & _
"{" & _
" try {" & _
"var ds = new Ajax.Web.DataSet();" & _
"var dt = new Ajax.Web.DataTable();" & _
"dt.addColumn('Control1Name', 'System.String');" & _
"dt.addColumn('Control1Value', 'System.String');" & _
"dt.addColumn('Control1Description', 'System.String');" & _
"dt.addColumn('Control2Name', 'System.String');" & _
"dt.addColumn('Control2Value', 'System.String');" & _
"dt.addColumn('Control2Description', 'System.String');" & _
"dt.addColumn('IsRequired', 'System.Boolean');" & _
"dt.addColumn('ValidationType', 'System.Int32');" & _
"ds.addTable(dt);" & _
"<DELTA>" & _
"var res = AjaxValidator.ValidateControls(ds);" & _
"if (res.value.Status == false) " & _
" {alert(res.value.Message);" & _
"document.getElementById(res.value.InvalidControlName).focus();" & _
"return false;" & _
"} else return true;" & _
"} catch(ex) {alert('Validation Exception:' + ex.description); " &_
"return false; }" & _
"}" & _
"</script>"
Dim nl As String = Environment.NewLine
Dim deltaCode As String = nl & "var <r> = {};" & nl & _
"<r>.Control1Name = '<hidControlValue1>';" & nl & _
"<r>.Control1Value = document.getElementById('<hidControlValue1>')." &_
"value;" & nl & _
"<r>.Control1Description = '<hidControlDesc1>';" & nl & _
"<r>.Control2Name = '<hidControlValue2>';" & nl & _
"<r>.Control2Value = document.getElementById('<hidControlValue2>')." &_
"value;" & nl & _
"<r>.Control2Description = '<hidControlDesc2>';" & nl & _
"<r>.IsRequired = <isRequired>;" & nl & _
"<r>.ValidationType = <type>;" & nl & _
"dt.addRow(<r>);" & nl
deltaCode = JsTryCatchIt(deltaCode, _
"Unable to find control <r>:<hidControlDesc1>")
Dim codeBuilder As New StringBuilder
For i As Integer = 0 To _registeredControlsList.Count - 1
Dim snippet As String = deltaCode
With _registeredControlsList(i)
snippet = snippet.Replace("<r>", "r" & i)
snippet = snippet.Replace("<hidControlDesc1>", .control1Desc)
snippet = snippet.Replace("<hidControlDesc2>", .control2Desc)
snippet = snippet.Replace("<isRequired>", _
.isRequired.ToString.ToLower)
snippet = snippet.Replace("<type>", _
CType(.type, Integer).ToString())
snippet = snippet.Replace("<hidControlValue1>", _
GetClientId(.control1))
snippet = snippet.Replace("<hidControlValue2>", _
GetClientId(.control2))
End With
codeBuilder.Append(snippet)
Next
scriptCode = scriptCode.Replace("<DELTA>", codeBuilder.ToString)
Page.ClientScript.RegisterStartupScript(Me.GetType, "validatorScript", _
scriptCode)
AppendToAttribute(_triggerControl, "onclick", _
"if(!_validatePage()) return false;")
End Sub
这样,验证用户控件的创建就完成了。下面的部分描述了如何在我们的应用程序页面中使用此验证控件,这非常简单。
整合:在 Web 页面中使用验证用户控件
创建一个 Web 窗体 AjaxValidationSample.aspx,并将验证用户控件拖放到其中。根据需要添加尽可能多的控件进行验证。在窗体的页面加载事件中,调用 RegisterValidationControls()
方法。在 RegisterValidationControls()
(或您选择的任何方法)内部,您需要提供一个触发器控件来触发验证。之后,调用 RegisterControl
或 RegisterControls
方法来注册您想要的控件。最后,调用 RegisterScript
方法来渲染 Ajax JavaScript。
以下代码显示了 AjaxValidationSample.aspx 及其后台代码的内容
HTML 代码
<%@ Page Language="vb" AutoEventWireup="false"
CodeBehind="AjaxValidationSample.aspx.vb"
Inherits="AjaxValidation.AjaxValidationSample" %>
<%@ Register Src="Validator.ascx" TagName="Validator" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Ajax Validation Sample</title>
</head>
<body>
<form id="form1" runat="server">
<table>
<tr>
<td colspan="2">
<uc1:Validator ID="Validator1" runat="server" />
</td>
</tr>
<tr>
<td>Email Address:</td>
<td><asp:TextBox ID="txtEmail" runat="server"
ToolTip="Email Address"></asp:TextBox></td>
</tr>
<tr>
<td>Date Range:</td>
<td><asp:TextBox ID="txtFrom" runat="server"
ToolTip="From Date"/><asp:TextBox ID="txtTo"
runat="server" ToolTip="To Date"/></td>
</tr>
</table>
<asp:Button ID="btnSubmit" Text="Submit" runat="server"/>
</form>
</body>
</html>
代码隐藏
Public Partial Class AjaxValidationSample
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object,_
ByVal e As System.EventArgs) Handles Me.Load
RegisterValidationControls()
End Sub
Private Sub RegisterValidationControls()
Validator1.TriggerControl = btnSubmit
Validator1.RegisterControl(txtEmail, ValidationType.EmailValidation, _
True)
Validator1.RegisterControls(txtFrom, txtTo, _
ValidationType.DateRangeValidation, True)
Validator1.RegisterScript()
End Sub
End Class
就是这样!在运行时,当表单加载时,JavaScript 会被加载并应用验证。以下是单击提交按钮后输出的屏幕截图。
范围
所提供的验证控件设计用于以批量模式处理单个控件验证和两个控件之间的验证。这意味着您可以用一个 Ajax 调用验证 10 个控件。
结论
我们已经看到了如何创建一个可扩展的基于 Ajax 的验证用户控件。为该控件添加更多类型的验证非常容易。所有需要做的就是定义一个新的 enum
并提供验证代码,验证控件将处理其余的事情。希望这对某人会有所帮助。编码愉快!
历史
- 2007 年 1 月 2 日 - 初始版本