向客户端脚本公开 Web 服务
更新:2007 年 11 月
利用 ASP.NET 的 AJAX 功能,可以在浏览器中使用客户端脚本来调用 ASP.NET Web 服务(.asmx 文件)。这可以改善用户在使用 Web 应用程序时的体验。页面可以在不进行回发和刷新整个页面的情况下调用基于服务器的方法,因为浏览器与 Web 服务器之间只传输数据。
本主题描述如何向在浏览器中运行的 JavaScript 提供 Web 服务。
ASP.NET 自动为 Web 服务创建 JavaScript 代理类。这些代理类派生自 Sys.Net.WebServiceProxy 类。可以通过调用 JavaScript 代理类的相应方法来调用 Web 服务方法。有关更多信息,请参见从客户端脚本调用 Web 服务。
使 Web 服务可从脚本访问
为了使 Web 服务能够从脚本访问,该服务必须是使用 ScriptServiceAttribute 属性限定其 Web 服务类的 .asmx Web 服务。从脚本调用的各个方法必须使用 WebMethodAttribute 属性限定。
下面的示例演示了 Web 服务代码中的这些属性。
[ScriptService]
public class SimpleWebService : System.Web.Services.WebService
{
[WebMethod]
public string EchoInput(String input)
{
// Method code goes here.
}
}
<ScriptService> _
Public Class SimpleWebService
Inherits System.Web.Services.WebService
<WebMethod> _
Public Function EchoInput(ByVal input As String) As String
' Method code goes here.
End Function
End Class
若要实现从脚本调用 Web 服务,必须在应用程序的 Web.config 文件中注册 ScriptHandlerFactory HTTP 处理程序。该处理程序处理从脚本发出的对 .asmx Web 服务的调用。下面的示例演示用于添加处理程序的 Web.config 元素。
说明: |
---|
这些配置设置已经包含在您在 Microsoft Visual Studio 2005 中创建的任何支持 AJAX 的新网站的 Web.config 文件模板中。 |
<system.web>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx"
type="System.Web.Script.Services.ScriptHandlerFactory"
validate="false"/>
</httpHandlers>
<system.web>
对于不是从 ASP.NET AJAX 脚本发出的 Web 服务调用,ScriptHandlerFactory 处理程序将调用委托给使用 SOAP 而不是 JSON 格式的默认处理程序。委托是自动执行的,您无需执行任何操作,除非您希望禁止对 Web 服务使用 SOAP 协议。在这种情况下,必须在 Web.config 文件中输入以下配置设置。
<system.web>
<webServices> <protocols> <clear/> </protocols> </webServices>
</system.web>
向 ASP.NET 网页中的客户端脚本公开 Web 服务
若要使 .asmx Web 服务能够从 ASP.NET 网页中的客户端脚本调用,必须向该网页添加一个 ScriptManager 控件。通过将 asp:ServiceReference 子元素添加到 ScriptManager 控件,然后将服务器引用 path 属性设置为 Web 服务的 URL,可以引用 Web 服务。ServiceReference 对象指示 ASP.NET 生成一个 JavaScript 代理类,用于从客户端脚本调用指定的 Web 服务。
下面的示例演示如何使一个名为 SimpleWebService.asmx 的 Web 服务能够从 ASP.NET 网页中的脚本调用。
<asp:ScriptManager runat="server" ID="scriptManager">
<Services>
<asp:ServiceReference
path="~/WebServices/SimpleWebService.asmx" />
</Services>
</asp:ScriptManager>
ServiceReference 对象只能引用与页位于同一域中的 Web 服务。Web 服务路径可以是相对路径、应用程序相对路径、域相对路径或绝对路径。对于绝对路径,必须确保该路径位于相同域中。
当呈现包含此 ScriptManager 控件的页时,该页会为 SimpleWebService.asmx Web 服务创建一个 JavaScript 代理类。该代理类的方法对应于 SimpleWebService.asmx 服务中的 Web 方法。该页还包含 JavaScript 代理类,这些代理类对应于用作 Web 服务方法的输入参数或返回值的服务器数据类型。这使您可以编写用于初始化这些参数的客户端脚本,并可以将这些参数传递给方法调用。
ServiceReference 对象的 InlineScript 属性指定在页中包含 JavaScript 代理类的方式。如果 InlineScript 设置为 false(默认值),将通过发出一个单独的请求来获取代理脚本。当多个页引用同一服务并且启用了浏览器缓存时,这种方式更加有效。
如果 InlineScript 设置为 true,代理类脚本将作为内联脚本块包含在页中。这可以通过减少网络请求的数量来提高性能。当页中存在很多个服务引用,而其他页未引用相同服务时,尤其如此。如果将 InlineScript 设置为 true,则必须使用相对路径。如果路径是域相对路径,则必须引用同一 Web 应用程序。
下面的示例演示一个从脚本调用的简单 Web 服务,该服务显示用户的输入并返回当前服务器时间。下面的示例演示通过客户端脚本发出服务调用的页。
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<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 EchoUserInput()
{
var echoElem = document.getElementById("EnteredValue");
Samples.AspNet.SimpleWebService.EchoInput(echoElem.value,
SucceededCallback);
}
// This is the callback function that
// processes the Web Service return value.
function SucceededCallback(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="SimpleWebService_VB.asmx" />
</Services>
</asp:ScriptManager>
<div>
<h2>Simple Web Service</h2>
<p>Calling a simple service that echoes the user's input and
returns the current server time.</p>
<input id="EnteredValue" type="text" />
<input id="EchoButton" type="button"
value="Echo" onclick="EchoUserInput()" />
</div>
</form>
<hr/>
<div>
<span id="Results"></span>
</div>
</body>
</html>
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<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 EchoUserInput()
{
var echoElem = document.getElementById("EnteredValue");
Samples.AspNet.SimpleWebService.EchoInput(echoElem.value,
SucceededCallback);
}
// This is the callback function that
// processes the Web Service return value.
function SucceededCallback(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="SimpleWebService.asmx" />
</Services>
</asp:ScriptManager>
<div>
<h2>Simple Web Service</h2>
<p>Calling a simple service that echoes the user's input and
returns the current server time.</p>
<input id="EnteredValue" type="text" />
<input id="EchoButton" type="button"
value="Echo" onclick="EchoUserInput()" />
</div>
</form>
<hr/>
<div>
<span id="Results"></span>
</div>
</body>
</html>
下面的示例演示通过客户端脚本调用的服务。
<%@ WebService Language="VB" Class="Samples.AspNet.SimpleWebService" %>
Imports System.Web
Imports System.Web.Services
Imports System.Xml
Imports System.Web.Services.Protocols
Imports System.Web.Script.Services
Namespace Samples.AspNet
<WebService(Namespace:="http://tempuri.org/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
Public Class SimpleWebService
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function EchoInput(ByVal input As String) As String
Dim inputString As String = Server.HtmlEncode(input)
If Not String.IsNullOrEmpty(inputString) Then
Return String.Format("You entered {0}. The " + _
"current time is {1}.", inputString, DateTime.Now)
Else
Return "The input string was null or empty."
End If
End Function 'EchoInput
End Class 'SimpleWebService
End Namespace
<%@ WebService Language="C#" Class="Samples.AspNet.SimpleWebService" %>
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 SimpleWebService : System.Web.Services.WebService
{
[WebMethod]
public string EchoInput(String input)
{
string inputString = Server.HtmlEncode(input);
if (!String.IsNullOrEmpty(inputString))
{
return String.Format("You entered {0}. The "
+ "current time is {1}.", inputString, DateTime.Now);
}
else
{
return "The input string was null or empty.";
}
}
}
}
在 ASP.NET 网页中调用静态方法
可以将静态页方法添加到 ASP.NET 页中并将其用作 Web 方法。然后,无需创建单独的 .asmx 文件即可从该页中的脚本调用这些方法,就好像这些方法是 Web 服务的一部分。若要在页中创建 Web 方法,请导入 System.Web.Services 命名空间,然后将 WebMethodAttribute 属性添加到每个要公开的静态方法。页方法必须在执行页方法调用的页中进行定义。
为了能够将静态页方法作为 Web 方法进行调用,必须将 ScriptManager 控件的 EnablePageMethods 属性设置为 true。
下面的示例演示如何从客户端脚本调用静态页方法以读写会话状态值。下面的示例演示了页方法。
<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Services" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
<WebMethod()> _
Public Shared Function GetSessionValue(ByVal key As String) As String
' Get session state value.
Return CStr(HttpContext.Current.Session(key))
End Function 'GetSessionValue
<WebMethod()> _
Public Shared Function SetSessionValue(ByVal key As String, _
ByVal value As String) As String
' Set session state value.
HttpContext.Current.Session(key) = value
Return CStr(HttpContext.Current.Session(key))
End Function 'SetSessionValue
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Using Page Methods with Session State</title>
<style type="text/css">
body { font: 11pt Trebuchet MS;
font-color: #000000;
padding-top: 72px;
text-align: center }
.text { font: 8pt Trebuchet MS }
</style>
</head>
<body>
<h2>Using Page Methods with Session State</h2>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1"
runat="server" EnablePageMethods="true">
<Scripts>
<asp:ScriptReference Path="PageMethod.js"/>
</Scripts>
</asp:ScriptManager>
</form>
<center>
<table>
<tr align="left">
<td>Write current date and time in session state:</td>
<td>
<input type="button"
onclick="SetSessionValue('SessionValue', Date())"
value="Write" />
</td>
</tr>
<tr align="left">
<td>Read current date and time from session state:</td>
<td>
<input type="button"
onclick="GetSessionValue('SessionValue')"
value="Read" />
</td>
</tr>
</table>
</center>
<hr/>
<span style="background-color:Aqua" id="ResultId"></span>
</body>
</html>
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Services" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
[WebMethod]
// Get session state value.
public static string GetSessionValue(string key)
{
return (string)HttpContext.Current.Session[key];
}
[WebMethod]
// Set session state value.
public static string SetSessionValue(string key, string value)
{
HttpContext.Current.Session[key] = value;
return (string)HttpContext.Current.Session[key];
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Using Page Methods with Session State</title>
<style type="text/css">
body { font: 11pt Trebuchet MS;
font-color: #000000;
padding-top: 72px;
text-align: center }
.text { font: 8pt Trebuchet MS }
</style>
</head>
<body>
<h2>Using Page Methods with Session State</h2>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1"
runat="server" EnablePageMethods="true">
<Scripts>
<asp:ScriptReference Path="PageMethod.js"/>
</Scripts>
</asp:ScriptManager>
</form>
<center>
<table>
<tr align="left">
<td>Write current date and time in session state:</td>
<td>
<input type="button"
onclick="SetSessionValue('SessionValue', Date())"
value="Write" />
</td>
</tr>
<tr align="left">
<td>Read current date and time from session state:</td>
<td>
<input type="button"
onclick="GetSessionValue('SessionValue')"
value="Read" />
</td>
</tr>
</table>
</center>
<hr/>
<span style="background-color:Aqua" id="ResultId"></span>
</body>
</html>
下面的示例演示如何使用脚本发出页方法调用。
// PageMethods.js
var displayElement;
// Initializes global variables and session state.
function pageLoad()
{
displayElement = $get("ResultId");
PageMethods.SetSessionValue("SessionValue", Date(),
OnSucceeded, OnFailed);
}
// Gets the session state value.
function GetSessionValue(key)
{
PageMethods.GetSessionValue(key,
OnSucceeded, OnFailed);
}
//Sets the session state value.
function SetSessionValue(key, value)
{
PageMethods.SetSessionValue(key, value,
OnSucceeded, OnFailed);
}
// Callback function invoked on successful
// completion of the page method.
function OnSucceeded(result, userContext, methodName)
{
if (methodName == "GetSessionValue")
{
displayElement.innerHTML = "Current session state value: " +
result;
}
}
// Callback function invoked on failure
// of the page method.
function OnFailed(error, userContext, methodName)
{
if(error !== null)
{
displayElement.innerHTML = "An error occurred: " +
error.get_message();
}
}
if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
有关会话状态的更多信息,请参见 ASP.NET 会话状态概述。