使用 Microsoft 登录
登录或创建帐户。
你好,
使用其他帐户。
你有多个帐户
选择要登录的帐户。

ASP.NET"支持语音"列

使用 XMLHTTP 的动态页面更新

为了根据需要自定义此列,我们希望邀请你提交有关感兴趣的主题以及您希望在将来的知识库文章和支持语音列中解决的问题的想法。 您可以使用"请求它"表单 提交想法和 反馈。 此列底部还有指向窗体的链接。

简介

我最喜爱的 Web 应用程序可用性学习方式之一是观察我的孩子在网站中导航。 她可以很好地利用 Internet,但是她几乎不知道低级别的技术方面 (她称之为") "的一切工作。



最近一个晚上,我看到我的孩子从一个大块头中欣赏一个电子商务应用程序。 她使用多个下拉列表向下钻取到产品列表,每个下拉列表都取自以前进行的选择。 她单击每个下拉列表中的某个项目时,该页面将发布回,用于获取下一个下拉列表的数据。 这一体验令她感到沮丧,因为她的印象是由于发回帖子而需要很长时间。



如果应用程序开发人员只使用 XMLHTTP 检索数据而不是发布回数据,则她经历的沮丧程度可能很容易得到缓解。 这就是本月的列内容。 我将展示如何使用 XMLHTTP 通过 Microsoft ASP.NET Web 服务的数据更新网页的一部分,而无需发回帖子。 这会非常酷! 相信我。

常规概述

XMLHTTP 的工作原理是从客户端向 Web 服务器发送请求并返回 XML 数据岛。 根据收到的 XML 的结构,可以使用 XSLT 或 XML DOM 对其进行操作,将页面的部分内容绑定到该数据。 这是一种非常强大的技术。

NoteMicrosoft 确实为 web 服务行为提供Internet Explorer,可快速轻松地ASP.NET Web 服务的异步调用。 但是,此行为不受支持,不是异步更新页面的最佳方法。 应改为使用 XMLHTTP!


在此列中的示例中,我将通过 XMLHTTP 对 ASP.NET Web 服务进行三次 Web 服务调用。 Web 服务将查询本地数据库上的 Northwind 数据库SQL Server以 XML 差异报的形式将数据集返回到客户端。 然后,我将使用 XML DOM 来分析该 XML 数据并动态更新页面的部分内容。 所有这些操作都无需发回帖子即可完成。

Web 服务

我将使用的 Web 服务名为 DynaProducts。 它是使用 C# ASP.NET的基本 Web 服务,包含以下三种方法。

  • GetCategories – 返回包含"类别"表中的所有类别的数据集。

  • GetProducts – 返回一个 DataSet,其中包含传递给该方法的类别的所有产品。

  • GetProductDetails – 返回一个 DataSet,其中包含其 ProductID 传递给该方法的产品的详细信息。

HTML 页面

有关此示例的第一个可能问题是,我通过 web 服务更新的页面ASP.NET不是ASP.NET页面。 它只是一个常规 HTML 页面。 但是,我已向页面添加了大量客户端 JavaScript,并且该脚本用于调用 Web 服务。



让我们看一下 HTML 页面的第一个代码片段。

var objHttp;
var objXmlDoc;

function getDataFromWS(methodName, dataSetName, wsParamValue, wsParamName)
{

// create the XML object
objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

if (objXmlDoc == null)
{
alert("Unable to create DOM document!");

} else {

// create an XmlHttp instance
objHttp = new ActiveXObject("Microsoft.XMLHTTP");


// Create the SOAP Envelope
strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +

" xsd=\"http://www.w3.org/2001/XMLSchema\"" +

" soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +

" <soap:Body>" +

" <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +

" </" + methodName + ">" +

" </soap:Body>" +

"</soap:Envelope>";


// Set up the post
objHttp.onreadystatechange = function(){

// a readyState of 4 means we're ready to use the data returned by XMLHTTP
if (objHttp.readyState == 4)
{

// get the return envelope
var szResponse = objHttp.responseText;

// load the return into an XML data island
objXmlDoc.loadXML(szResponse);

if (objXmlDoc.parseError.errorCode != 0) {
var xmlErr = objXmlDoc.parseError;
alert("You have error " + xmlErr.reason);
} else {

switch(dataSetName)
{
case "CategoriesDS":
processCategory();
break;

case "ProductsDS":
processProducts();
break;

case "ProductDetailDS":
processProductDetails();
break;

}
}

}
}

var szUrl;
szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;

if (wsParamValue != null)
{

szUrl += "?" + wsParamName + "=" + wsParamValue;
}

// send the POST to the Web service
objHttp.open("POST", szUrl, true);
objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
objHttp.send(strEnvelope);
}
}

这是页面中最大的一段代码,我想详细查看一下,以便了解具体内容。



在此脚本块的顶部,我创建了两个变量:objHttp 和 objXmlDoc。 这些变量用于我的 XMLHTTP 对象和我的 XML DOM 对象。 紧接在此之后是 getDataFromWS 函数的函数定义。 这是负责对 Web 服务进行客户端调用的函数。 它采用以下四个参数,其中两个参数是可选的:

  • methodName – 在 Web 服务上调用的方法的名称。

  • dataSetName – Web 服务返回的数据集的名称。

  • wsParamValue – 传递给 Web 服务的参数的值(如果适用)。 (可选)

  • wsParamName – 传递给 Web 服务的参数的名称(如果适用)。 (可选)

让我们将 getDataFromWS 函数分解成多个部分,并讨论每个部分。 下面是第一个代码片段:

// create the XML object
objXmlDoc = new ActiveXObject("Msxml2.DOMDocument");

if (objXmlDoc == null)
{
alert("Unable to create DOM document!");

} else {

// create an XMLHTTP instance
objHttp = new ActiveXObject("Microsoft.XMLHTTP");

此代码块创建 XMLHTTP 对象和 XML 文档对象。 接下来,开始创建 SOAP 信封。

// Create the SOAP Envelope
strEnvelope = "<soap:Envelope xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +

" xsd=\"http://www.w3.org/2001/XMLSchema\"" +

" soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +

" <soap:Body>" +

" <" + methodName + " xmlns=\"http://jimcoaddins.com/DynaProducts\">" +

" </" + methodName + ">" +

" </soap:Body>" +

"</soap:Envelope>";

在此代码中,我将 SOAP 信封分配给字符串变量,以便将其传递给 Web 服务。 实际上,发现如何为 Web 服务设置 SOAP 信封的格式非常简单。 只需浏览到 Web 服务,并单击其中一种方法即可查看该方法的 SOAP 信封。 例如,下面是浏览到为本文创建的 wsXMLHTTP Web 服务的 GetCategories 方法时看到的内容: 备用文本ASP.NET 告知如何为 HTTP POST 和 HTTP GET 设置



SOAP 信封的格式。 在本文演示的示例中,我将使用 HTTP POST。



目前为止,一切都好。 现在,我们来看下一部分代码。

// Set up the post
objHttp.onreadystatechange = function(){

// a readyState of 4means we're ready to use thedata returned byXMLHTTP
if (objHttp.readyState == 4)
{

// getthe return envelope
varszResponse= objHttp.responseText;

// loadthe return into an XML data island
objXmlDoc.loadXML(szResponse);

if (objXmlDoc.parseError.errorCode != 0) {
var xmlErr =objXmlDoc.parseError;
alert("You have error " + xmlErr.reason);
}
else
{

switch(dataSetName)
{
case "CategoriesDS":
processCategory();
break;
case "ProductsDS":
processProducts();
break;
case "ProductDetailDS":
processProductDetails();
break;

}
}

通过 XMLHTTP 提出请求时,XMLHTTP 对象使用 readyState 属性来跟踪请求的状态。 从 Web 服务收到所有数据后,readyState 属性将更改为值 4。 XMLHTTP 对象的 onreadystatechange 属性允许设置在 readyState 属性更改时将调用的回调函数。 通过确保已接收整个数据,我可以一直不处理该数据,直到我准备就绪。



收到所有数据后,使用 responseText 属性创建包含响应的 XML 数据岛。 如你所知,来自 Web 服务的响应采用 XML 格式。 在这种情况下,我将返回 Microsoft ADO.NET DataSet。



此代码块的下一部分使用 switch 语句基于从 Web 服务返回的 DataSet 的名称调用相应的函数。 稍后我将详细介绍这些函数的代码。


现在,让我们看看实际执行 XMLHTTP 请求的代码。

var szUrl;
szUrl = "http://dadatop/wsXmlHttp/DynaProducts.asmx/" + methodName;

if (wsParamValue != null)
{

szUrl += "?" + wsParamName + "=" + wsParamValue;
}

// send the POST to the Web service
objHttp.open("POST", szUrl, true);
objHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
objHttp.send(strEnvelope);

为清楚起见,变量 szUrl 包含用于调用 Web 服务的 URL。 然后,我有一个 if 语句,该语句会确认作为 QueryString 值传递的任何参数。 在环境中,可能需要将参数添加到 SOAP 信封。 无论哪种方式都正常工作。



接下来调用 XMLHTTP 对象的 open 方法。 我已将前三个参数用于 open 方法;方法、URL 和布尔值,该值指定调用是否异步。
重要:如果你正在此处进行异步调用,则必须通过 onreadystatechanged 属性设置回调函数。

设置内容类型的请求标头后,使用前面填充的字符串变量将请求作为 SOAP 信封发送。



现在,我们已翻遍了生成 XMLHTTP 请求的所有代码。 现在,让我们看一下在浏览器中处理接口以及处理来自 Web 服务调用的响应的代码。

首先,我们将查看页面首次加载时调用的函数。

function getCategories()
{

var func = "getDataFromWS('GetCategories', 'CategoriesDS')";
document.all.lblCategoryDropdown.innerText =
"Please wait while data is retrieved...";
window.setTimeout(func, 1);

}

我在此函数中执行的第一件事是创建一个变量来存储 getDataFromWS 的函数签名。 我这样做是因为我将在此函数的末尾调用 window.setTimeout 以调用 getDataFromWS 函数。 此方法的目的是允许在等待 Web 服务调用完成时向用户显示状态。 请注意,我正在更改 DIV 的内部图文集以显示一条消息,指示正在检索数据。 然后,通过 window.setTimeout 调用计划 getDataFromWS 函数,将其设置为在一毫秒后运行。

处理 Web 服务响应

请记住,之前我使用了 onreadystatechanged 属性来配置回调函数。 另请记住,回调函数包含一个 switch 语句,该语句基于 DataSet 名称调用特定函数。 在这种情况下,DataSet 名称为 CategoriesDS。 因此,将从回调函数调用 processCategory 函数。 让我们看看该函数,了解如何使用 XML DOM 分析来自 Web 服务的响应。

function processCategory()
{

// get an XML data island with the category data
objNodeList = objXmlDoc.getElementsByTagName("Categories");

// add default value to the drop-down
document.forms[0].drpCategory.options[0] = new Option("Select a Category", 0);

// walk through the nodeList and populate the drop-down
for (var i = 0; i < objNodeList.length; i++)
{
var dataNodeList;
var textNode;
var valueNode;

dataNodeList = objNodeList[i].childNodes;
valueNode = dataNodeList.item(0);
textNode = dataNodeList.item(1);

document.forms[0].drpCategory.options[i + 1] =
new Option(textNode.text, valueNode.text);
document.all.lblCategoryDropdown.innerText = "Select a Category:";
document.forms[0].drpCategory.style.visibility = "visible";

}

}

请记住,getDataFromWS 函数将响应中的 XML 加载到 objXmlDoc 对象中。 在 processCategory 函数中,我接受该 XML 并分析它以填充 Category 下拉列表。



要做的第一件事是使用 XML 响应的一部分创建 IXMLDOMNodeList 对象。 从 Web 服务调用返回的 DataSet 将返回为差异图,该响应中我真正感兴趣的唯一部分是已插入到 DataSet 的 DataTable 数据。 可以通过从包含 DataTable 的 XML 块创建 IXMLDOMNodeList 对象来执行此操作。



如果查看 Web 服务的代码,将看到创建名为"类别"的 DataTable,并将其添加到 DataSet。 从 Web 服务返回 XML 时,DataSet 包含在 <CategoriesDS> 块中,DataTable 的每一行都包含在单独的 <Categories> 块中,如下面的 XML 文件中所示。

可从 Microsoft 下载中心下载以下文件: 下载 下载GetCategories.xml
包。
下载 下载WSXMLHTTP.exe包。若要详细了解如何下载 Microsoft 支持文件,请单击以下文章编号,在 Microsoft 知识库中查看该文章:

119591 如何从 Microsoft 扫描的联机服务获取
Microsoft 支持文件以获取病毒。 Microsoft 使用的是文件发布时可以获得的最新病毒检测软件。 该文件存储在安全性得到增强的服务器上,以防止对文件进行未经授权的更改。


若要获取包含该 DataTable 的 XML 块,请使用以下代码:

objNodeList = objXmlDoc.getElementsByTagName("Categories");

这会返回一个 IXMLDOMNodeList 对象,该对象包含节点<类别>对象。 然后,使用 for 循环循环访问该列表。

// walk through the nodeList and populate the drop-down
for (var i = 0; i < objNodeList.length; i++)
{
var dataNodeList;
var textNode;
var valueNode;

dataNodeList = objNodeList[i].childNodes;
valueNode = dataNodeList.item(0);
textNode = dataNodeList.item(1);

document.forms[0].drpCategory.options[i + 1] =
new Option(textNode.text, valueNode.text);
document.all.lblCategoryDropdown.innerText = "Select a Category:";
document.forms[0].drpCategory.style.visibility = "visible";

}

我已经知道,每个 <Categories> 节点都有两个我需要的节点:<ID> 节点和 <CategoryName>节点。 因此,我要做的第一件事是创建新的 IXMLDOMNodeList,并在其中填充当前"类别"节点<节点>节点。

dataNodeList = objNodeList[i].childNodes;

然后,使用项方法访问填充下拉列表所需的两个节点。 第一个节点包含数据库中的 CategoryID 字段,第二个节点包含数据库中的 CategoryName 字段。 我创建新的 Option 对象,将文本设置为 CategoryName,将值设置为 CategoryID,并将其添加到 drpCategory 下拉列表。 其余函数中使用的代码使用相同的方法从 XML 响应提取所需的数据,并填充页面部分。

请注意,我们在此处处理少量数据,使用 DOM 是提取所需的数据的好办法。 如果要处理大量数据,可以选择改为使用 XSLT。

如何使一切正常工作

现在,我已介绍了所有这些工作原理的细小细节,现在可以了解如何使用包含的示例文件来了解它如何为自己工作。

部署 Web 服务

若要部署 ASP.NET Web 服务,只需将附加的 Web 服务示例解压缩到 Web 服务器的根目录。 然后,需要打开 DynaProducts.asmx 的代码并更改连接字符串。 至少需要输入 SA 密码。 完成该更改后,重新编译 Web 服务。

部署 HTML 文件

HTML 文件包含一个名为 szUrl 的变量,其中包含 Web 服务的 URL。 在靠近函数底部的 getDataFromWS 函数中可以找到此变量。 需要将 URL 更改为上面部署的 Web 服务的 URL。


部署 Web 服务和 HTML 文件后,浏览到 HTML 文件。 加载时,类别下拉列表将填充对 Web 服务的第一个 XMLHTTP 请求。 填充完成后,选择一个类别以启动下一个 XMLHTTP 请求,该请求填充"产品"下拉列表。 从"产品"下拉列表中选择产品将在表中填充有关该产品的数据。



请注意,在任何此类 XMLHTTP 请求期间,页面不会发回。 这就是 XMLHTTP 请求的美感。 如果我在大型页面上完成了此操作,页面也会保持其滚动位置,而不会在用户看到"闪烁"。 如果你询问我,这是一些非常强大的功能!



还有一件事:本文使用 XMLHTTP 查询 Web 服务。 我可以轻松使用它来请求 ASPX 页面或 ASP 页面。 使用此技术的可能性是无限的。 希望 XMLHTTP 在将来的 Web 应用程序开发中有用。

与始终一样,使用"请求它"表单,随时在将来的列中或 Microsoft 知识库中提交有关要 处理的主题的想法

需要更多帮助?

需要更多选项?

了解订阅权益、浏览培训课程、了解如何保护设备等。

社区可帮助你提出和回答问题、提供反馈,并听取经验丰富专家的意见。

此信息是否有帮助?

你对语言质量的满意程度如何?
哪些因素影响了你的体验?
按“提交”即表示你的反馈将用于改进 Microsoft 产品和服务。 你的 IT 管理员将能够收集此数据。 隐私声明。

谢谢您的反馈!

×