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

利用 jQuery 和 ASP.NET Web 服务实现零回发业务网站

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (8投票s)

2011年9月16日

CPOL

6分钟阅读

viewsIcon

35117

downloadIcon

615

本文详细介绍如何使用 jQuery 和 ASP.NET Web 服务来实现零回发网站。

引言

本文介绍如何利用 jQuery 和 ASP.NET Web 服务编写零回发(无部分/完整回发,即无表单提交)的业务网站。本文还展示了如何从客户端 jQuery 代码调用以 .NET 对象作为参数的 Web 服务,以及如何处理 Web 服务调用返回的接收到的对象。

背景

让我们回到基本概念。为什么要使用控件?原因是我们如果不使用控件,就只能纯粹地打印文本信息,用户将很难与网站进行交互。表单提交(回发)的整个故事就由此开始。服务器如何知道发生了用户交互,并且需要执行某些操作?答案就是回发。很快,回发就变得非常令人讨厌,并催生了 AJAX 技术,实现了异步部分回发,其中只有特定更新面板中的控件才会回发到服务器,当然,还伴随着 ViewState 令人讨厌的负担。对于此类回发,更新面板同样会经历几乎所有的事件,如 Page_InitPage_Load、控件事件、Page_PreRender 等,除了 Page_Render。很快,即使这样有时也会因为带宽负载过重而变得慢得令人讨厌。那么,如果根本没有表单提交或部分回发,会怎样呢?应该有一种机制,允许用户在客户端与控件进行交互(这是众所周知且容易的),然后让服务器响应在浏览器级别发生的此类交互(我现在将介绍这一点)。我们知道客户端脚本可以调用带有 [ScriptService] 属性的 ASP.NET Web 服务。因此,如果我们能将相关控件的状态放入一个对象中,并通过 jQuery(客户端)调用这样的服务,然后获得作为 aforesaid 服务返回值的另一个对象,并随后在客户端更改控件的状态,那么我们的工作就完成了。用户现在知道,根据他们的交互,服务器已经响应,并且网站也相应地反映了这一点。那么,如果这就是所需,为什么还需要回发呢?

Using the Code

代码是一个简单的 ASP.NET Web 站点解决方案,其中包含一个母版页和一个额外的 Web 内容表单,仅用于说明概念。仅使用了三个服务器控件:一个 asp:Button,一个 asp:Label 和一个 asp:DropDownList

我们必须首先添加 .js 文件 jquery-1.4.1.jsJSON2.jsJSON2.js 是从 http://www.JSON.org/json2.js 下载的。它包含非常有用的 JSON.stringify() 函数,该函数可以 JSON 序列化 JavaScript 对象,使其可以作为参数发送到接受类似 .NET 对象的 Web 服务调用中。我们应该首先在母版页的 <head> .... </head> 部分包含对 .js 文件的引用。

<script type="text/javascript" src="jquery-1.4.1.js"></script>
<script type="text/javascript" src="JSON2.js"></script>
<script type="text/javascript" language="javascript">
window.history.forward(1);
</script>

在上面的代码中,我们包含了 .js 文件的引用,并禁用了网站范围内的浏览器后退按钮。我们还在 <form> .... </form> 标签内包含了一个 ScriptManager

<asp:ScriptManager ID="KovairScriptManager" runat="server" 
EnableScriptGlobalization="true" 
EnablePageMethods="true"> </asp:ScriptManager>

现在,我们进入 Web 内容表单 Default.aspx

现在声明控件。

<asp:Button ID="btnRetrieveData" runat="server" 
Text="GetData" Width="175px" 
OnClientClick = "javascript:return GetStudents();" UseSubmitBehavior="false"/>

<asp:DropDownList ID="ddlStudents" runat="server" 
Height="16px" style="width: 77px" 
Width="250px"></asp:DropDownList> 

<asp:Label ID="lblResult" runat="server" 
Text="Label" Height="50px" Width="100px">
</asp:Label>

现在,我们在数据库 Student 中创建两个表。

USE
[Student] 
GO
CREATE TABLE [dbo].[StuRec]( 
[RollNo] [int] IDENTITY(1,1) NOT NULL, 
[Name] [nvarchar](50) NULL, 
CONSTRAINT [PK_StuRec] PRIMARY KEY CLUSTERED ([RollNo] ASC )
GO
CREATE TABLE [dbo].[StuMark]( 
[RollNo] [int] NOT NULL, 
[Marks] [int] NULL, 
CONSTRAINT [PK_StuMark] PRIMARY KEY CLUSTERED ([RollNo] ASC)
GO
ALTER TABLE [dbo].[StuMark] WITH CHECK 
ADD CONSTRAINT [FK_StuMark_StuRec] 
FOREIGN KEY([RollNo]) REFERENCES [dbo].[StuRec] ([RollNo]) 
GO

我们添加了两个表:StuRec ,包含学生的 RollNo Name ;以及 StuMark,包含学生的 RollNo Marks 。这只是为了说明这样一个概念:从客户端,如果下拉列表中选择了一个学生,那么通过从 StuMark 表中检索相应的记录,应该在标签中显示该学生的相应分数。用适当的数据填充这些表。

因此,我们首先编写 Web 服务:一个用于从 StuRec 表中获取所有学生,另一个用于从 StuMark 表中获取特定学生的成绩。请注意,Web 服务类已用 [ScriptService] 属性进行修饰,以便可以从客户端脚本调用它。

[WebService(Namespace = "https:///Kovair.Site")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class KovairWebService : System.Web.Services.WebService {
public KovairWebService () 
{
}

[WebMethod]
public List<ListItem> GetStudents() {
string connStr = 
ConfigurationManager.ConnectionStrings["KovairSiteConnectionString"].ToString();
SqlConnection conn = new SqlConnection(connStr);
SqlCommand comm = new SqlCommand();
comm.CommandText = "SELECT RollNo, Name From dbo.StuRec";
comm.Connection = conn;
SqlDataAdapter da = new SqlDataAdapter(comm);
DataSet ds = new DataSet();
conn.Open();
da.Fill(ds, "StudentRecord");
conn.Close();
List<ListItem> stuList = new List<ListItem>();
if (ds.Tables != null)
{
    int recordCount = ds.Tables["StudentRecord"].Rows.Count;
    if (recordCount > 0)
    {
        DataTable dtab = ds.Tables["StudentRecord"];
        for (int i = 0; i < recordCount; i++)
        {
            stuList.Add(new ListItem(
            dtab.Rows[i]["Name"].ToString(),
            dtab.Rows[i]["RollNo"].ToString()
            ));
        }
     }
   }
return stuList;
}
[WebMethod]
public StuMark GetStudentDetail(StuRec stu)
{
string connStr = 
ConfigurationManager.ConnectionStrings["KovairSiteConnectionString"].ToString();
SqlConnection conn = new SqlConnection(connStr);
int roll = stu.RollNo;
SqlCommand comm = new SqlCommand();
comm.CommandText = 
@"SELECT R.RollNo, M.Marks From dbo.StuMark M INNER JOIN 
dbo.StuRec R ON M.RollNo = R.RollNo WHERE R.RollNo = @rollNo";
comm.Parameters.Add(new SqlParameter("@rollNo", SqlDbType.Int)).Value = roll;
comm.Connection = conn;
SqlDataAdapter da = new SqlDataAdapter(comm);
DataSet ds = new DataSet();
conn.Open();
da.Fill(ds, "StudentDetailRecord");
conn.Close();
string marks = String.Empty;
if (ds.Tables != null)
{
    int recordCount = ds.Tables["StudentDetailRecord"].Rows.Count;
    if (recordCount > 0)
    {
       DataTable dtab = ds.Tables["StudentDetailRecord"];
       marks = dtab.Rows[0]["Marks"].ToString();
     }
}
StuMark sm = new StuMark();
sm.RollNo = stu.RollNo;
sm.Marks = Convert.ToInt32(marks);
return sm;
}
}

在第二个 Web 服务中,我们有一个类型为 StuRec 的参数 stu ,它返回一个类型为 StuMark 的对象。对象定义如下所示。它们是 .NET 对象。

public class StuMark
{
public int RollNo { get; set; }
public int Marks { get; set; }
}
public class StuRec
{
public int RollNo { get; set; }
public string Name { get; set; }
}

现在,我们将看到如何调用第一个 Web 方法 GetStudents() ,它返回一个 ListItem 类型的 List 对象。为什么我们要返回 List<ListItem>?因为我们想将这些 ListItems 添加到客户端的 DropdownList 中。如果点击按钮,应该调用 JavaScript 方法 GetStudents() ,因为它通过按钮的 OnClientClick 属性绑定。我们利用 jQuery 的 $.ajax() 实用工具通过 jQuery 从客户端调用 Web 服务。代码简洁、干净且易于阅读。因此,人们发现 jQuery 比 JavaScript 更好。

function GetStudents() {
$('#<%=ddlStudents.ClientID %>').empty().append
('<option selected="selected" value="0">Loading...</option>');
$.ajax({
type: 'POST',
url: 'https:///Kovair.Site/KovairWebService.asmx/GetStudents',
data: {},
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(response, status) {
var list = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
var control = $('#<%=ddlStudents.ClientID %>');
control.removeAttr("disabled");
control.empty().append('<option selected="selected" value="0">Please select</option>');
$.each(list, function() {
control.append('<option value ="' + this['Value'] + 
'">"' + this['Text'] + '"</option>');
});
},
failure: function(response) {
alert(response.d);
}
}
);
}

jQuery 使用 JSON。因此,我们看到内容类型是 JSON,数据类型是 JSON。URL 的形式是 Web 服务 URI / Web 方法。在成功时,我们收集返回的 List<ListItem>,并运行一个 $.each() jQuery 函数来迭代它,并将其添加到客户端的 dropdownlist 中。所以,没有表单提交,没有回发。

但真正有趣的是第二个 Web 方法,它有一个类型为 StuRec 的参数 stu ,这是一个 .NET 对象。现在,jQuery 如何传递一个 .NET 对象作为参数?答案是 JSON 和 JavaScript 对象。我们创建一个类似的 JavaScript 对象,并使用 JSON2.js 中编写的 JSON.stringify() 函数将其转换为适当的 JSON string 。代码如下所示:

var NewStudent = {};
NewStudent.RollNo = 22;
NewStudent.Name = "Jacob";
// Create a data transfer object (DTO) with the proper structure.
var DTO = { 'stu': NewStudent };
  
$(function() {
   $('#<%=ddlStudents.ClientID %>').change(function(e) {
        var rollNo = this.options[this.selectedIndex].value;
        var name = this.options[this.selectedIndex].text;
        NewStudent.RollNo = rollNo;
        NewStudent.Name = name;
        $.ajax({
             type: 'POST',
             url: 'https:///Kovair.Site/KovairWebService.asmx/GetStudentDetail',
             data: JSON.stringify(DTO),
             contentType: 'application/json; charset=utf-8',
             dataType: 'json',
             success: function(response, status) {
   var list = (typeof response.d) == 'string' ? eval('(' + response.d + ')') : response.d;
       var oup = "RollNo: " + list.RollNo.toString() + " Marks: " + list.Marks.toString();
       $('#<%=lblResult.ClientID %>').html(oup);
      },
      failure: function(response) {
      alert(response.d);
      }
    }
   );
  }
 )
}
);

在上面的方法中,我们使用了 $document.ready() 的简写形式,也可以是 $.ready() 简单地 $()。我们在初始表单加载时注册 dropdownlist 的 change 事件,其中指定了在页面初始加载后,如果 dropdownlist 的选择发生任何变化时要执行的操作。在此之前,我们在 JavaScript 中创建了一个对象 NewStudent ,它收集所选值和所选文本的值,然后使用 JSON.stringify 将其转换为 JSON 文本,以便作为参数传递给 Web 服务。成功时,返回对象的字段值再次收集到一个 JavaScript 对象变量中,然后显示在一个标签中。

关注点

我们已经学会了如何通过 $.ajax() 调用一个带有 [ScriptService] 属性的 Web 服务,作为对客户端(浏览器)捕获的控件事件的响应。因此,我们已经学会了如何获取数据并在客户端显示它,而无需提交表单,正如 default.aspx 的代码隐藏文件所示,它只有一个代码隐藏类声明,如下所示:

public partial class _Default : System.Web.UI.Page
{
}

历史

  • 2011 年 9 月 16 日:初次发布
© . All rights reserved.