AJAX 在这里 - 第二部分:ASP.NET 集成






4.69/5 (31投票s)
2005年4月21日
6分钟阅读

278567

797
ASP.NET 中的异步 JavaScript 和 XML。
引言
这是关于 AJAX(或异步 JavaScript 和 XML)系列三篇文章中的第二篇。如果你还没有阅读第一部分,我建议你阅读本系列文章的第一部分。在第一部分中,我们介绍了 AJAX 的客户端部分,特别是用于发起异步 Web 请求的 JavaScript 对象。本文的目标是为服务器端 (ASP.NET) 开发人员提供易于集成到其代码中的内容(最好没有太多花哨或专有的变通方法)。
好东西
我们将介绍示例代码(参见上面的下载源文件),分别显示在清单1和2中,即 Article.aspx 和 Article.aspx.cs。代码示例使用 C# 编写,但该技术可用于任何 .NET 兼容语言。
Article.aspx
Article.aspx 是如何将 AJAX 应用到实际 Web 应用程序的示例。越来越多的网站要求用户在访问大部分网站内容之前进行注册。这通常涉及选择用户名和密码,以及输入一些其他信息,例如电子邮件地址或邮政编码。很少有网站允许两个用户拥有相同的用户名。所以,假设我选择“JohnDoe”作为我的用户名,我点击注册按钮,等待一段时间,结果网页重新加载,显示我请求的用户名不可用。这个过程可能会持续一段时间,直到我选择一个唯一的用户名。AJAX 允许我们在用户输入用户名时对其进行验证。无需回发到服务器,也无需下载所有不可用用户名的完整列表。Article.aspx 展示了这种“即时验证”的功能。
JavaScript
为了验证正在输入的用户名,我们需要将当前用户名发送到服务器,等待请求完成,然后根据结果采取行动。我通过创建 CallBackObject
(详细信息请参见AJAX 在这里 – 第一部分)简化了此过程。
var Cbo = new CallBackObject();
Cbo.OnComplete = Cbo_Complete;
Cbo.OnError = Cbo_Error;
在这里,我们正在创建一个新的 CallBackObject
并告诉该对象:“当我的 Web 请求完成时,我希望你运行函数 Cbo_Complete
”,以及“如果在请求期间发生任何不良情况,我希望你运行函数 Cbo_Error
”。由于 Web 请求是异步的,我们不知道服务器何时会精确完成我们的请求,因此我们设置了 OnComplete
事件,这样我们就不必坐着干等。
function Cbo_Complete(responseText, responseXML)
{
var msg = document.getElementById('lblMessage');
if( responseText == 'True' )
{
msg.innerHTML = 'CallBack - Username Available!';
msg.style.color = 'green';
}
else
{
msg.innerHTML = 'CallBack - Username Unavailable!';
msg.style.color = 'red';
}
}
当我们的网络请求完成时,我们希望通知用户。如果输入的用户名可用,我们的网络请求将返回 True
,如果输入的用户名不可用,则返回 False
。如果用户名可用,我们用绿色文本显示一条积极消息;否则,我们用红色文本显示一条消极消息。
function Cbo_Error(status, statusText, responseText)
{
alert(responseText);
}
如果在Web请求期间发生错误,我们会使用标准警报框显示错误。
function CheckUsername(Username)
{
var msg = document.getElementById('lblMessage');
if( Username.length > 0 )
{
Cbo.DoCallBack('txtUsername', '');
}
else
{
Cbo.AbortCallBack();
msg.innerHTML = '';
}
}
函数 CheckUsername
启动到服务器的异步请求(或回调)。首先,我们确保问题中的用户名不为空,然后我们调用 Cbo.DoCallBack
,传入用户名输入框的 ID(稍后详细介绍)。如果用户名为空,我们取消当前正在进行的任何回调,并清除所有消息。
<asp:TextBox id=txtUsername
onkeyup=CheckUsername(this.value);
OnTextChanged="txtUsername_TextChanged"
Runat="server"></asp:TextBox>
最后,在 HTML 中,我们将用户名文本框的 onkeyup
属性设置为执行 CheckUsername
并传递文本框的当前值。我们使用 onkeyup
,以便在用户输入他们想要的用户名时提供即时反馈。
这就是使我们的 AJAX 示例工作所需的客户端代码。
ASP.NET
CallBackObject
的美妙之处在于它本质上允许 JavaScript 代码触发服务器端事件。让我们再次看看 HTML 片段。
<asp:TextBox id=txtUsername
onkeyup=CheckUsername(this.value);
OnTextChanged="txtUsername_TextChanged"
Runat="server"></asp:TextBox>
请注意我们如何将 OnTextChanged
(一个服务器端事件)设置为 txtUsername_TextChanged
。正如我们稍后将看到的(参见清单 2),txtUsername_TextChanged
是用 C# 编写的 ASP.NET 事件,它确定 txtUsername
的值是否是可用用户名。此事件是由客户端使用 JavaScript 通过此行触发的
Cbo.DoCallBack('txtUsername', '');
这不是很酷吗?您正在使用客户端代码触发服务器端事件,而无需重新加载整个页面。让我们更深入地了解一下 txtUsername_TextChanged
。
protected void txtUsername_TextChanged(object sender, System.EventArgs e)
{
if( !CallBackHelper.IsCallBack )
return;
string uName = txtUsername.Text;
try
{
CallBackHelper.Write( IsUsernameAvailable(uName).ToString() );
}
catch( Exception ex )
{
CallBackHelper.HandleError( ex );
}
}
首先,我们使用 CallBackHelper
(包含在源文件中)检查当前请求是否为回调。这与使用 Page.IsPostBack
完全相同,您需要根据请求的上下文执行不同的操作。接下来,我们获取 txtUsername
的值并将其传递给我们的 IsUsernameAvailable
函数。此函数返回一个布尔值,指示用户名是否可用。最后,我们使用 CallBackHelper.Write
将该值写回客户端。请注意我们如何将处理包装在 try
/catch
块中,如果发生任何不良情况,我们使用 CallBackHelper.HandleError
。这确保了客户端会收到错误通知。
private bool IsUsernameAvailable( string Username )
{
bool isAvailable = true;
switch( Username.ToLower() )
{
case "bill":
case "william":
case "christopher":
case "pierce":
case "zonebit":
isAvailable = false;
break;
}
return isAvailable;
}
IsUsernameAvailable
是一个简单的测试函数,通常您会在数据库中查找请求的用户名以查看其是否有效。
我还特意在页面上放置了一个 asp:button
,以展示我们的回调实现与标准 ASP.NET 实现之间的区别。如果您点击“检查用户名可用性”按钮,您将回发整个页面以验证用户名,这可能需要更长时间,此外,用户在服务器返回结果之前无法继续填写表单。
试用一下
请访问此网站,亲自体验AJAX的魅力。输入一个字母,您应该会看到用户名可用性的视觉指示。继续输入,您应该会不断获得更新(尝试输入“bill”或“pierce”以获取不可用的用户名)。您也可以点击按钮,使用标准回发执行相同的操作。
但这到底意味着什么?
我们可以向客户端返回任何字符串,包括 XML。在此示例中,我们只需要一个简单的 true
/false
来指示用户名是否可用。另一个示例可能是从客户端发送邮政编码,并从服务器返回城市和州。现在您可以从客户端与服务器端代码进行交互,可能性是无限的。
结论
ASP.NET 为我们处理了事件管道。只要您使用 ASP.NET 控件并实现标准事件,例如 SelectedIndexChanged
、TextChanged
、Click
,您就可以使用 CallBackObject
和 CallBackHelper
轻松地在 ASP.NET 应用程序中使用 AJAX。
那然后呢?
如果你还没读腻我的长篇大论,请查看本系列文章的第三部分,我们将创建一个自动完成文本框。自动完成文本框是一个 ASP.NET 控件,它会在你输入时自动补全文本。太棒了!
清单 1 - Article.aspx
<%@ Page language="c#" Codebehind="Article.aspx.cs"
AutoEventWireup="false" Inherits="AJAX.Article" %>
<HEAD>
<title>AJAX was Here</title>
<script type="text/javascript" src="CallBackObject.js"></script>
</HEAD>
<form id="frmAjax" method="post" runat="server">
<script type="text/javascript">
var Cbo = new CallBackObject();
Cbo.OnComplete = Cbo_Complete;
Cbo.OnError = Cbo_Error;
function CheckUsername(Username)
{
var msg = document.getElementById('lblMessage');
if( Username.length > 0 )
{
Cbo.DoCallBack('txtUsername', '');
}
else
{
Cbo.AbortCallBack();
msg.innerHTML = '';
}
}
function Cbo_Complete(responseText, responseXML)
{
var msg = document.getElementById('lblMessage');
if( responseText == 'True' )
{
msg.innerHTML = 'CallBack - Username Available!';
msg.style.color = 'green';
}
else
{
msg.innerHTML = 'CallBack - Username Unavailable!';
msg.style.color = 'red';
}
}
function Cbo_Error(status, statusText, responseText)
{
alert(responseText);
}
</script>
<table width="100%">
<tr>
<td>Username:</td>
<td>
<asp:TextBox Runat="server" ID="txtUsername"
onkeyup="CheckUsername(this.value);"
OnTextChanged="txtUsername_TextChanged" />
</td>
<td align="left" width="100%">
<asp:Label Runat="server" ID="lblMessage"/>
</td>
</tr>
<tr>
<td colspan="3" align="left">
<asp:Button Runat="server" ID="btnCheckUsername"
OnClick="btnCheckUsername_Click"
Text="Check Username Availability" />
</td>
</tr>
</table>
</form>
清单 2 - Article.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using WCPierce.Web;
namespace AJAX
{
public class Article : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox txtUsername;
protected System.Web.UI.WebControls.Label lblMessage;
protected System.Web.UI.WebControls.Button btnCheckUsername;
private void Page_Load(object sender, System.EventArgs e) { }
#region Web Form Designer generated code
protected void txtUsername_TextChanged(object sender, System.EventArgs e)
{
if( !CallBackHelper.IsCallBack )
return;
string uName = txtUsername.Text;
try
{
CallBackHelper.Write( IsUsernameAvailable(uName).ToString() );
}
catch( Exception ex )
{
CallBackHelper.HandleError( ex );
}
}
protected void btnCheckUsername_Click(object sender, System.EventArgs e)
{
string uName = txtUsername.Text;
if( IsUsernameAvailable( uName ) )
{
lblMessage.Text = "Server - Username Available!";
lblMessage.ForeColor = Color.Green;
lblMessage.Visible = true;
}
else
{
lblMessage.Text = "Server - Username Unavailable!";
lblMessage.ForeColor = Color.Red;
lblMessage.Visible = true;
}
//Simulate 5 second delay
System.Threading.Thread.Sleep(5000);
}
private bool IsUsernameAvailable( string Username )
{
bool isAvailable = true;
switch( Username.ToLower() )
{
case "bill":
case "william":
case "christopher":
case "pierce":
case "zonebit":
isAvailable = false;
break;
}
return isAvailable;
}
}
}
历史
- 2005-04-21 – 首次发布。