本主题介绍如何从支持 AJAX 的 ASP.NET 网页中的客户端脚本访问 Web 服务。这些服务可以是您创建的自定义服务,也可以是内置的应用程序服务。应用程序服务是作为 ASP.NET AJAX 的一部分提供的,包括身份验证、角色和配置文件服务。
自定义 Web 服务可以采用 ASP.NET Web 服务(.asmx 服务)或 Windows Communication Foundation (WCF) 服务(.svc 服务)的形式。
本主题包含以下信息:
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
在下列情况下使用 WCF 和 ASP.NET:
-
如果已创建 WCF 服务,则可以添加终结点以使得支持 AJAX 的网页中的脚本可以访问这些服务。有关更多信息,请参见向客户端脚本公开 WCF 服务。
-
如果已创建 ASP.NET Web (.asmx) 服务,则可以修改这些服务以使得支持 AJAX 的网页中的脚本可以访问相同的服务。有关更多信息,请参见向客户端脚本公开 Web 服务。
-
如果需要创建要从 ASP.NET AJAX 网页访问的自定义 Web 服务,则可以将该服务作为 WCF 服务或 ASP.NET Web 服务(.asmx 文件)来实现。
-
可以使用内置的 ASP.NET 应用程序服务,通过在支持 AJAX 的网页中运行的客户端脚本访问用户的身份验证、角色和配置文件信息。有关更多信息,请参见将 Forms 身份验证用于 ASP.NET AJAX。
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
使用 ASP.NET 可以创建可从网页中的客户端脚本访问的 Web 服务。页面与服务器通过 Web 服务通信层进行通信,该通信层使用 AJAX 技术进行 Web 服务调用。数据在客户端与服务器之间进行异步交换(通常采用 JSON 格式)。
针对 AJAX 客户端的客户端-服务器通信
在支持 AJAX 的网页中,浏览器向服务器发出对页面的初始请求,然后向 Web 服务发出对数据的后续异步请求。客户端通信元素采用代理类(从服务器下载)和核心客户端脚本库的形式。服务器通信元素是处理程序和自定义服务。下图显示了客户端与服务器之间的通信中涉及的元素。
![AJAX 中的 Web 服务客户端服务器通信](http://i.msdn.microsoft.com/Bb515101.AJAX_ClientServer%28zh-cn,VS.90%29.png)
AJAX 客户端结构
浏览器使用代理类调用 Web 服务方法。代理类是由服务器自动生成并在页面加载时下载到浏览器中的脚本。代理类提供一个客户端对象,该对象表示某个 Web 服务的已公开方法。
为了调用 Web 服务方法,客户端脚本会调用代理类的相应方法。调用是通过 XMLHTTP 对象异步进行的。
Web 服务通信层包含使代理类可以进行服务调用的库脚本类型。有关更多信息,请参见 Sys.Net 命名空间中包含的类。
代理类和核心 Web 服务通信层中的代码隐藏了 XMLHTTP 的复杂性和浏览器之间的差异。这简化了调用 Web 服务所必需的客户端脚本。
发出 Web 服务请求有以下两种方式:
-
使用 HTTP POST 谓词调用 Web 服务。POST 请求具有一个包含浏览器发送到服务器的数据的正文。该正文没有大小限制。因此,可以在数据大小超过 GET 请求的固有大小限制时使用 POST 请求。客户端将请求序列化为 JSON 格式并将其作为 POST 数据发送到服务器。服务器将 JSON 数据反序列化为 .NET Framework 类型并进行实际的 Web 服务调用。在响应过程中,服务器对返回值进行序列化并将这些值传递回客户端,而客户端再将这些值反序列化为 JavaScript 对象以便进行处理。
-
使用 HTTP GET 谓词调用 Web 服务。这与 POST 请求的功能类似,只不过具有以下区别:
-
客户端使用查询字符串将参数发送到服务器。
-
GET 请求只能调用使用 ScriptMethodAttribute 属性配置的 Web 服务方法。
-
数据大小限制为浏览器所允许的 URL 长度。
说明:
对于在服务器上修改数据或公开关键信息的方法调用,应避免使用 GET 请求。在 GET 请求中,由浏览器将消息编码为 URL,因此更容易遭到篡改。对于 GET 和 POST 请求,您应遵循安全准则以保护敏感数据。
-
下图显示了 ASP.NET AJAX 客户端结构。
![AJAX 中的 Web 服务客户端体系结构](http://i.msdn.microsoft.com/Bb515101.AJAX_ClientArch%28zh-cn,VS.90%29.png)
客户端结构的元素包括位于核心库中的 Web 服务通信层以及下载的服务代理类(在页面上使用)。图中显示的各个元素如下所示:
-
自定义服务代理类。这些类包含由服务器自动生成并下载到浏览器中的客户端脚本。代理类为页面中使用的每个 WCF 或 ASMX 服务提供一个对象。(也就是说,代理类为页面中 ScriptManager 控件的 ServiceReferences 元素中的每个项提供一个对象。)在客户端脚本中调用代理方法会创建一个对服务器上相应 Web 服务方法的异步请求。
-
身份验证代理类。AuthenticationService 代理类由服务器身份验证应用程序服务生成。该代理类使得用户可以在浏览器中通过 JavaScript 进行登录或注销,而不必进行到服务器的往返过程。
-
角色代理类。RoleService 代理类由服务器角色应用程序服务生成。使用该代理类可以通过 JavaScript 对用户进行分组并将每个组视为一个单元,而不必进行到服务器的往返过程。对于启用或拒绝对服务器上资源的访问,这可能十分有用。
-
配置文件代理类。ProfileService 代理类由服务器配置文件应用程序服务生成。该代理类使得当前用户的配置文件信息通过 JavaScript 对客户端可用,而不必进行到服务器的往返过程。
-
页面方法代理类。此代理类为客户端脚本提供脚本基础结构以调用 ASP.NET 页中的静态方法(就好像这些方法是 Web 服务方法一样)。有关更多信息,请参见从客户端脚本调用 Web 服务。
-
Web 服务通信层。这是包含客户端脚本类型的库。这些类型使得浏览器(客户端)可以与服务器上的服务进行通信。这些类型还使客户端应用程序避免了在客户端与服务器之间建立和维护异步通信的复杂性。它们封装提供异步功能的浏览器 XMLHTTP 对象,并使得客户端应用程序可以独立于浏览器。Web 服务通信层的主要元素如下:
-
WebRequest. 此元素提供用于发出 Web 请求的客户端脚本功能。有关更多信息,请参见 WebRequest 类。
-
WebRequestManager. 此元素管理由 WebRequest 对象向关联的执行器对象发出的 Web 请求流。有关更多信息,请参见 WebRequestManager 类。
-
XmlHttpExecutor. 此元素利用浏览器的 XMLHTTP 支持发出异步网络请求。有关更多信息,请参见 XmlHttpExecutor 类。
-
JSON 序列化。将 JavaScript 对象序列化为 JSON 格式。使用 JavaScript eval 函数可进行反序列化。有关更多信息,请参见 JavaScriptSerializer 类。
-
默认序列化格式为 JSON,但是 Web 服务和 ASP.NET 网页中的单个方法可以返回其他格式(如 XML)。可以通过属性来指定方法的序列化格式。例如,对于某个 ASMX 服务,可以设置 ScriptMethodAttribute 属性以使某个 Web 服务方法返回 XML 数据,如下面的示例中所示:
[ScriptMethod(ResponseFormat.Xml)] <ScriptMethod(ResponseFormat.Xml)>
AJAX 服务器结构
下图显示了 AJAX 服务器结构,该结构包含启用与客户端应用程序的通信的元素。
![AJAX 中的 Web 服务服务器体系结构](http://i.msdn.microsoft.com/Bb515101.AJAX_ServerArch%28zh-cn,VS.90%29.png)
服务器结构的元素包括具有 HTTP 处理程序和序列化类的 Web 服务通信层、自定义服务、页面方法以及应用程序服务。图中显示的各个元素如下所示:
-
自定义 Web 服务。这些服务提供您实现的服务功能并将相应的响应返回给客户端。自定义 Web 服务可以是 ASP.NET 或 WCF 服务。Web 服务通信层自动生成可从客户端脚本异步调用的客户端脚本代理类。
-
页面方法。此组件使得 ASP.NET 页中的方法可以如同 Web 服务方法一样被调用。页面方法必须在执行页面方法调用的页面中进行定义。
-
身份验证服务。身份验证服务生成身份验证代理类,该代理类使得用户可以通过客户端 JavaScript 进行登录或注销。此应用程序服务始终可用,因此不必将其实例化。有关更多信息,请参见将 Forms 身份验证用于 ASP.NET AJAX。
-
角色服务。角色服务生成角色代理类,该代理类使得客户端 JavaScript 可以访问当前经过身份验证的用户的角色信息。此应用程序服务始终可用,因此不必将其实例化。有关更多信息,请参见通过 ASP.NET AJAX 使用角色信息。
-
配置文件服务。配置文件服务生成配置文件代理类,该代理类使得客户端 JavaScript 可以获取和设置与当前请求相关联的用户的配置文件属性。此应用程序服务始终可用,因此不必将其实例化。有关更多信息,请参见将配置文件信息与 ASP.NET AJAX 一起使用。
-
JSON 序列化。使用服务器 JSON 序列化组件可以在常见 .NET Framework 类型与 JSON 格式之间进行可自定义的序列化和反序列。有关更多信息,请参见 JavaScriptSerializer。
-
XML 序列化。Web 服务通信层支持 XML 序列化,用于对 Web 服务发出 SOAP 请求,并用于从对 Web 服务的 JSON 请求返回 XML 类型。
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
下面的示例演示如何从客户端脚本调用 ASP.NET 和 WCF 服务。在本文档的其他部分中提供了有关如何从客户端脚本调用应用程序服务的示例。在本主题后面的部分中提供了相关链接。
在 AJAX 中调用 Web 服务方法
使用 .NET Framework 可以通过客户端脚本从浏览器异步调用 ASP.NET Web 服务 (.asmx) 方法。页面可以在不进行回发和刷新整个页面的情况下调用基于服务器的方法,因为浏览器与服务器之间只传输数据。
下面的示例演示如何在 ASP.NET 网页中公开 Web 服务方法。
<%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head id="Head1" runat="server"> <style type="text/css"> body { font: 11pt Trebuchet MS; font-color: #000000; padding-top: 72px; text-align: center } .text { font: 8pt Trebuchet MS } </style> <title>Simple Web Service</title> <script type="text/javascript"> // This function calls the Web Service method. function GetServerTime() { Samples.AspNet.ServerTime.GetServerTime(OnSucceeded); } // This is the callback function that // processes the Web Service return value. function OnSucceeded(result) { var RsltElem = document.getElementById("Results"); RsltElem.innerHTML = result; } </script> </head> <body> <form id="Form1" runat="server"> <asp:ScriptManager runat="server" ID="scriptManager"> <Services> <asp:ServiceReference path="ServerTime.asmx" /> </Services> </asp:ScriptManager> <div> <h2>Server Time</h2> <p>Calling a service that returns the current server time.</p> <input id="EchoButton" type="button" value="GetTime" οnclick="GetServerTime()" /> </div> </form> <hr/> <div> <span id="Results"></span> </div> </body> </html>
下面的示例演示一个网页以及由页面脚本调用的相关 Web 服务。
<%@ WebService Language="C#" Class="Samples.AspNet.ServerTime" %> using System; using System.Web; using System.Web.Services; using System.Xml; using System.Web.Services.Protocols; using System.Web.Script.Services; namespace Samples.AspNet { [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [ScriptService] public class ServerTime : System.Web.Services.WebService { [WebMethod] public string GetServerTime() { return String.Format("The server time is {0}.", DateTime.Now); } } }
从 AJAX 客户端发出 HTTP 请求
上面的示例演示如何通过调用为 Web 服务自动生成的代理类来从客户端脚本调用 Web 服务。还可以从客户端脚本对 Web 服务进行较低级别的调用。如果您需要管理通信层或检查要发送到服务器或从服务器发送的数据,则可能需要这样做。若要通过这种方式调用 Web 服务,请使用 WebRequest 类。
下面的示例演示如何使用 WebRequest 对象实现连接到指定 URL(HTTP 终点)的 GET 和 POST Web 请求。
// ConnectingEndPoints.js var resultElement; function pageLoad() { resultElement = $get("ResultId"); } // This function performs a GET Web request. function GetWebRequest() { alert("Performing Get Web request."); // Instantiate a WebRequest. var wRequest = new Sys.Net.WebRequest(); // Set the request URL. wRequest.set_url("getTarget.htm"); alert("Target Url: getTarget.htm"); // Set the request verb. wRequest.set_httpVerb("GET"); // Set the request callback function. wRequest.add_completed(OnWebRequestCompleted); // Clear the results area. resultElement.innerHTML = ""; // Execute the request. wRequest.invoke(); } // This function performs a POST Web request. function PostWebRequest() { alert("Performing Post Web request."); // Instantiate a WebRequest. var wRequest = new Sys.Net.WebRequest(); // Set the request URL. wRequest.set_url("postTarget.aspx"); alert("Target Url: postTarget.aspx"); // Set the request verb. wRequest.set_httpVerb("POST"); // Set the request handler. wRequest.add_completed(OnWebRequestCompleted); // Set the body for he POST. var requestBody = "Message=Hello! Do you hear me?"; wRequest.set_body(requestBody); wRequest.get_headers()["Content-Length"] = requestBody.length; // Clear the results area. resultElement.innerHTML = ""; // Execute the request. wRequest.invoke(); } // This callback function processes the // request return values. It is called asynchronously // by the current executor. function OnWebRequestCompleted(executor, eventArgs) { if(executor.get_responseAvailable()) { // Clear the previous results. resultElement.innerHTML = ""; // Display Web request status. resultElement.innerHTML += "Status: [" + executor.get_statusCode() + " " + executor.get_statusText() + "]" + "<br/>"; // Display Web request headers. resultElement.innerHTML += "Headers: "; resultElement.innerHTML += executor.getAllResponseHeaders() + "<br/>"; // Display Web request body. resultElement.innerHTML += "Body:"; if(document.all) resultElement.innerText += executor.get_responseData(); else resultElement.textContent += executor.get_responseData(); } } if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
在 AJAX 中调用 WCF 服务操作
可以从客户端脚本异步调用 Windows Communication Foundation (WCF) 服务 (.svc),方法与调用基于 .asmx 的服务基本相似。下面的示例演示如何在 ASP.NET 网页中公开和调用 WCF 服务操作。
<%@ Page Language="C#" AutoEventWireup="true"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head runat="server"> <style type="text/css"> body { font: 11pt Trebuchet MS; font-color: #000000; padding-top: 72px; text-align: center } .text { font: 8pt Trebuchet MS } </style> <title>Simple WCF Service Page</title> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="SimpleService.svc/ws"/> </Services> <Scripts> <asp:ScriptReference Path="service.js" /> </Scripts> </asp:ScriptManager> <div> <h2>Simple WCF Service</h2> <input type='button' name="clickme" value="Greetings" οnclick="javascript:OnClick()" /> <input type='button' name="clickme2" value="Greetings2" οnclick="javascript:OnClick2()" /> <hr/> <div> <span id="Results"></span> </div> </div> </form> </body> </html>
var ServiceProxy; function pageLoad() { ServiceProxy = new ISimpleService(); ServiceProxy.set_defaultSucceededCallback(SucceededCallback); } function OnClick() { // var myService = new ISimpleService(); ServiceProxy.HelloWorld1("George"); } function OnClick2() { var dc = new DataContractType(); dc.FirstName = "George"; dc.LastName = "Washington"; ServiceProxy.HelloWorld2(dc); } // This is the callback function that // processes the Web Service return value. function SucceededCallback(result, userContext, methodName) { var RsltElem = document.getElementById("Results"); RsltElem.innerHTML = result + " from " + methodName + "."; } if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
using System; using System.Web; using System.Collections; using System.Collections.Generic; using System.Threading; using System.Xml; using System.Xml.Serialization; using System.Text; using System.IO; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.ServiceModel.Channels; using System.ServiceModel.Activation; // This a WCF service which consists of a contract, // defined below as ISimpleService, and DataContractType, // a class which implements that interface, see SimpleService, // and configuration entries that specify behaviors associated with // that implementation (see <system.serviceModel> in web.config) namespace Aspnet.Samples { [ServiceContract()] public interface ISimpleService { [OperationContract] string HelloWorld1(string value1); [OperationContract] string HelloWorld2(DataContractType dataContractValue1); } [ServiceBehavior(IncludeExceptionDetailInFaults = true)] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class SimpleService : ISimpleService { public SimpleService() { } public string HelloWorld1(string value1) { return "Hello " + value1; } public string HelloWorld2(DataContractType dataContractValue1) { return "Hello " + dataContractValue1.FirstName + " " + dataContractValue1.LastName; } } [DataContract] public class DataContractType { string firstName; string lastName; [DataMember] public string FirstName { get { return firstName; } set { firstName = value; } } [DataMember] public string LastName { get { return lastName; } set { lastName = value; } } } }
其他示例
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
下表列出了与可从客户端脚本调用的 Web 服务相关联的主要类。
客户端命名空间
名称 | 说明 |
---|---|
此命名空间包含的类可管理 ASP.NET AJAX 客户端应用程序与服务器上 Web 服务之间的通信。Sys.Net 命名空间属于 Microsoft AJAX Library 的一部分。 | |
此命名空间包含的类与 ASP.NET AJAX 客户端应用程序的数据序列化相关。 | |
此命名空间包含的类型在 AJAX.NET 客户端应用程序中提供对 ASP.NET 身份验证服务、配置文件服务以及其他应用程序服务的脚本访问。Sys.Services 命名空间属于 Microsoft AJAX Library 的一部分。 |
服务器命名空间
名称 | 说明 |
---|---|
此命名空间包含的类为托管类型提供 JavaScript 对象表示法 (JSON) 序列化和反序列化。还提供用于自定义序列化行为的扩展性功能。 |
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)
![](http://i.msdn.microsoft.com/platform/Controls/CollapsibleArea/resources/minus.gif)