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

使用 jQuery AJAX 和 JSON 解析器保存 ASP.NET 表单数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (21投票s)

2009年10月27日

CPOL

7分钟阅读

viewsIcon

177814

downloadIcon

7239

使用 jQuery AJAX 和 JSON.Net 解析器处理 ASP.NET Web 表单数据并避免页面回发。

引言

我之所以写下这些,是因为我自己也曾苦恼于难以找到好的示例代码来实现我想要的功能。基本上,我希望我的 ASP.NET 页面(其中有一个用于输入费用项目的表单)能够实现以下功能:

  1. 当我点击表单上的“保存”按钮时,我不希望发生回发,因为回发会干扰表单上的某些内容;不仅仅是为了避免回发而这样做。为了实现这一点,我选择使用 jQuery AJAX Post 将 JSON 格式的表单数据发送到另一个 ASP.NET 页面进行处理。是的,我本来可以直接使用 ASP.NET AJAX Controls Toolkit 中的 UpdatePanel,但在这种情况下,这不是我想要的。
  2. AJAX 处理页面将检索 JSON 数据对象并进行数据库更新。
  3. 数据库更新完成后,页面将向发起 AJAX 调用的地方发送响应文本,并更新前端页面。

我的目标很简单,但它花费的时间比我预期的要多。原因很简单,因为这一次,我找不到足够的参考资料来指导我,所以我不得不花费大量时间通过试错法开发解决方案。因此,一旦我找到了解决方案,我告诉自己我需要与他人分享,因为我过去通过查看其他程序员的帖子从社区中受益匪多。

通过 jQuery 通配符选择器访问表单元素

我遇到的第一个挑战是检索所有服务器绑定的表单元素——无论是独立的 Web 控件还是用户控件中的 Web 控件。可以使用 Web 控件的 ClientID,但我不喜欢将太多服务器标签 <%=var%> 与 JavaScript 混合,而且它们可能会影响 JavaScript 性能。值得庆幸的是,jQuery 通配符选择器使这变得简单而干净。

这是一个如何实现此操作的示例

var recordid = $(“[id$=’txtRecordID’]”).val();

这将获取服务器端文本框控件中的文本值

<asp:TextBox ID="txtRecordID" runat="server" Width="100px">
</asp:TextBox>

但是 Web 用户控件中的 TextBox 呢?这就是我使用通配符的原因——获取客户端 ID 以服务器控件 ID 结尾的元素。通常,如果我只是将 TextBox 控件放置在 Web 表单上,客户端 ID 将与我在服务器端使用的 ID 完全相同;在这种情况下

$(“#txtRecordID”)

将返回与以下内容相同的元素对象

$(“[id$=’txtRecordID’]”)

但大多数情况下,我们会将某些 Web 控件分组到用户控件中,然后在 Web 表单上使用用户控件。在这种情况下,$(“#txtRecordID”) 将一无所获,因为现在您已将用户控件 ID 添加到 TextBox 的客户端 ID 中,因此现在,您将改为使用**通配符选择器**:$(“[id$=’txtRecordID’]”)。为了确保通配符返回唯一的元素,您可以添加用户控件服务器 ID,使其看起来像这样:

$(“[id$=’ucMyControl_txtRecordID’]”)

(在某些情况下,您可能会有两个或更多同名为 txtRecordID 的服务器控件,它们位于嵌入在同一 Web 表单中的不同用户控件中,那么您绝对需要将用户控件 ID 添加到 jQuery 通配符搜索中。我从某个时候的 Web 社区中获取了这种搜索以特定服务器 ID 结尾的元素的语法,但我无法再次找到源以在此处提供参考 URL。但我确实在撰写本文时在 www.emadibrahim.com 上遇到了一个类似的帖子,该帖子使用通配符搜索以特定 ID 开头的元素,语法如下:$(“[id^=pnl]).hide() - 隐藏所有控制 ID 以“pnl”开头的 div。)

通过 jQuery AJAX 发送 JSON 格式的数据

现在我已经通过 jQuery 通配符选择器清除了访问服务器端元素的障碍,我收集了数据并将它们串成 JSON 格式。JSON 只是 XML 格式的另一种轻量级替代方案,这是我简化的 JSON 数据字符串版本:

var json=”{‘RecordID’:’” + 
   $(“[id$=’txtRecordID’]”).val() + “’,’ItemName’:’” + 
   escape($(“[id$=’txtItemName’]”).val()) + “’,’CategoryID’:’” + 
   (“[id$=’ddlCategories’]”).val() + “’}”;

我将表单数据打包成 JSON 格式的字符串,只是因为我希望在线路的另一端使用 JSON.Net API 工具来解析它。我在所有文本字段前面使用了“escape”函数,以编码任何可能导致 JSON 解析器出错的奇怪字符,例如撇号。

接下来,我使用如下语法通过 jQuery AJAX 发送数据

var to=”DataProcessor.aspx?Save=1”;
var options = {
            type: "POST",
            url: to,
            data: json,
            contentType: "application/json;charset=utf-8",
            dataType: "json",
            async: false,
            success: function(response) {
                //alert("success: " + response);
            },
            error: function(msg) { alert(msg); }
        };

        var returnText = $.ajax(options).responseText;

这里,成功部分的 response 与从 $.ajax 返回的 responseText 相同。

从 Request.InputStream 检索 JSON 数据

然后,我进入 DataProcessor.aspx 代码隐藏文件,并执行以下步骤来检索和解析数据

  1. 使用此语法检查 Request 对象的 Content Type
  2. if (Request.ContentType.Contains("json") && 
        Request.QueryString["Save"]!=null)
          SaveMyData();
  3. 函数 SaveMyData 通过读取 Request 对象的 InputStream 来检索 JSON 数据,如下所示
  4. System.IO.StreamReader sr = new  System.IO.StreamReader(Request.InputStream);
    string line = "";
    line = sr.ReadToEnd();
    Console.WriteLine(line);

此时,字符串变量 line 包含一个 JSON 格式的字符串,例如

"{'ItemName':'Steve%27s%20Demo%20Item','CategoryID':'1','RecordID':''}"

我本来可以创建自己的函数来解析这个字符串并完成它。但是,当外面已经有了名为 JSON.Net 的东西时,我为什么要重新发明轮子呢?当然,我在 http://james.networking.com 上找到了所需的 API,并下载了 .NET 3.5 版本的库。按照下载附带的说明,我将 Newtonsoft.Json.dll 程序集添加到我的项目并导入命名空间 Newtonsoft.Json.Linq 到页面类;然后就有了——只需一行代码即可完成解析

JObject jo = JObject.Parse(line);

一旦我的 JSON 格式字符串变量 line 被解析,我就可以使用以下代码访问每个属性

Console.WriteLine((string)jo["RecordID"]);
Console.WriteLine(Server.UrlDecode((string)jo["ItemName"]));

还记得我在 DataForm.aspx 中将表单数据打包成 JSON 字符串时,对 ItemName 进行了 escape 操作吗?这里,我使用 Server.UrlDecode 实现了“unescape”的等效操作,这样“%20”会变回空格,“%27s”会变回“’s”,依此类推。在通过 JObject 解析器运行从 Request.InputStream 下载的数据之前,您不希望进行 UrlDecode,因为一些对 JSON 不友好的字符,如撇号(“'”)会使解析器崩溃。因此,只在 JObject.Parse() 之后进行 UrlDecode,并且只对字符串类型的每个单独属性进行。数据解析后,我在数据层中处理它们,并通过简单地调用 Response.Write() 将记录 ID 返回到前端页面。为了简化演示,我没有在这里包含任何数据库逻辑;相反,我只是返回了从前端页面上的类别下拉列表中在 JSON 字符串中传递的“CategoryID”,以指示数据库更新是成功还是失败

Response.Write((string)jo["CategoryID"]);

这就是我到达 jQuery.ajax(options).responseText 的原因。您还可以打包一个长 HTML 字符串并将其返回到 .ajax().responsText 以在前端页面上呈现。

现在,我回到首页并按如下方式检索 responseText

var returnText = $.ajax(options).responseText;
//alert(returnText);
if (returnText > 0) {
  $("[id$='txtRecordID']").html( returnText);
  $("#divMsg").html("<font color=blue>Record saved successfully.</font>");         
  //$("#divMsg").addClass("SuccessMsg"); //if you prefer to use class
}
else {
    $("#divMsg").html("<font color=red>Record was not saved successfully.</font>");         
    //$("#divMsg").addClass("ErrorMsg"); //if you prefer to use class
}

摘要

将它们全部结合起来,事情是这样运作的:使用 jQuery 通配符选择器 $(“[id$=’serversidecontrolid’]”) 检索存储在服务器控件(如 TextBoxDropDownList)中的表单数据,将它们构建成 JSON 字符串,然后使用 jQuery.Ajax() 将 JSON 数据 POST 到另一个 ASP.NET 页面进行处理;使用 System.IO.StreamReader 从另一端读取 Request.InputStream 对象来下载 JSON 数据,然后使用 JSON.Net 提供的 JSON 解析器 API 将 JSON 数据字符串解析为 JObject。数据保存后,我们使用 Response.Write 将结果返回到前端页面。

我对这个轻量级解决方案感到满意,它帮助我摆脱了笨重的 ASP.NET AJAX UpdatePanel,克服了页面回发。我撰写本文(也是我在 CodeProject 上的第一篇文章)的目标是分享我的研究并连接各个部分,以便其他人不必重复我刚开始时所经历的挫败感,当时我只能在这里找到一点,在那里找到一点。

© . All rights reserved.