65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 使用 Ajax 进行验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.16/5 (9投票s)

2007年1月4日

CPOL

5分钟阅读

viewsIcon

148129

downloadIcon

2014

本文介绍如何使用 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

以下是创建的示例页面的输出。

Simple Ajax output

构建验证控件

我们创建一个 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()(或您选择的任何方法)内部,您需要提供一个触发器控件来触发验证。之后,调用 RegisterControlRegisterControls 方法来注册您想要的控件。最后,调用 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 会被加载并应用验证。以下是单击提交按钮后输出的屏幕截图。

Simple Ajax output

范围

所提供的验证控件设计用于以批量模式处理单个控件验证和两个控件之间的验证。这意味着您可以用一个 Ajax 调用验证 10 个控件。

结论

我们已经看到了如何创建一个可扩展的基于 Ajax 的验证用户控件。为该控件添加更多类型的验证非常容易。所有需要做的就是定义一个新的 enum 并提供验证代码,验证控件将处理其余的事情。希望这对某人会有所帮助。编码愉快!

历史

  • 2007 年 1 月 2 日 - 初始版本
© . All rights reserved.