AJAX for Beginners (Part 3) - 在 ASP.NET 网站中从 JavaScript 调用服务器端方法和使用 Web 服务






4.96/5 (33投票s)
如何使用 ASP.NET AJAX 框架调用服务器端定义的方法,以及如何从 JavaScript 调用和使用 Web 服务。
这个迷你系列共有三篇文章
- AJAX for Beginners (Part 1) - 理解 ASP.NET AJAX 服务器控件
- AJAX for Beginners (Part 2) - 使用 XMLHttpRequest 和 jQuery AJAX 实现级联下拉列表
- AJAX for Beginners (Part 3) - 在 ASP.NET 网站中从 JavaScript 调用服务器端方法和使用 Web 服务
引言
在本文中,我们将尝试了解如何使用 ASP.NET AJAX 框架从客户端 JavaScript 调用服务器端定义的方法,即代码隐藏。我们还将探讨如何从 JavaScript 调用和使用 Web 服务。
背景
在我们的应用程序中,有很多时候我们希望在客户端拥有已在服务器端存在的功能。如果我们有独立的代码块在服务器端运行,那么就没有必要在客户端用 JavaScript 重写它。我们可以直接使用 ASP.NET Ajax 框架从服务器端调用方法。
使用服务器端代码的另一个好处是,我们可以获得服务器端语言和 API 的所有好处,并将结果返回到客户端。这有时非常有用,因为 C# 比 JavaScript 强大得多,而且 .NET Framework 提供了更广泛的功能。
我们还可以使用 ASP.NET AJAX 框架从 JavaScript 调用和使用 Web 服务。能够从 JavaScript 调用和使用 Web 服务,使我们能够使用 Web 服务创建高度响应的用户界面。
注意:使用 ASP.NET AJAX 框架时有一些限制。从客户端调用的服务器端方法必须是静态的,并且页面上的任何控件都不能在被客户端调用的服务器端代码中引用。因此,当我有可以根据输入数据调用并产生输出的独立算法时,此功能非常有用。
Using the Code
所有这些功能以及客户端和服务器之间的通信都由 ASP.NET AJAX 框架负责。要使用 ASP.NET AJAX 框架,我们只需在页面上放置一个 ScriptManager
控件,它将处理其余的事情。
要执行上述所有任务,我们需要编写包含实际功能的服务器端代码以及调用这些服务器端代码的 JavaScript 代码。负责客户端和服务器之间通信的所有样板代码都是 ASP.NET AJAX 框架的责任。让我们通过查看示例应用程序来尝试理解如何做到这一点。
调用简单的服务器端方法
因此,最基本的方法是在服务器端有一个方法,然后从 JavaScript 调用它。让我们首先在我们的代码隐藏文件中定义一个函数,它将简单地返回一个 string
消息。
[WebMethod]
public static string GetMessage()
{
return "Dummy Message";
}
为了使该方法可以从客户端脚本调用,我们需要将其设为 static
并使用 WebMethod
属性进行装饰/标记。
为了能够调用服务器端方法,我们需要做的第一件事是在 ScriptManager
控件中将 EnablePageMethods="true"
设置为 true。
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"/>
现在,让我们在 aspx
页面上放置一个按钮,该按钮将使用 JavaScript 调用此方法。
<asp:Button ID="Button1" runat="server" Text="Get Message"
OnClientClick="CallServerMethod(); return false;" />
CallServerMethod
方法是负责调用服务器端方法的 JavaScript 方法。返回 false
是为了抑制导致回发的默认操作。现在让我们看看实际调用服务器端方法的 JavaScript 函数。
function CallServerMethod()
{
// call the server side method here
PageMethods.GetMessage(OnSuccess);
}
调用服务器端方法的正确方法是调用页面中定义的、使用 PageMethods
的方法。调用无参数函数需要传递的参数是回调函数的名称,该回调函数将在获取结果时被调用。让我们看看这个回调函数。
function OnSuccess(result)
{
alert(result);
}
现在,当我们运行此页面时,将调用 CallServerMethod
。在此方法中,我们将使用 PageMethods
调用服务器端方法,并传递回调函数 OnSuccess
的名称。服务器端方法的返回值将作为参数传递到我们的回调函数中,即 result。让我们运行页面以查看结果。
传递值并从服务器端方法获取结果
现在我们能够从客户端调用一个简单的方法了,让我们看看如何将值从客户端传递到服务器端函数。为此,让我们尝试编写一个简单的计算器功能。让我们从用户那里获取两个输入,并将它们传递到服务器端,从服务器端获取结果并显示给用户。如果输入无效,服务器端应向我们发送错误,我们将向用户显示错误。
现在,为了做到这一点,我们首先需要两个输入字段和一个按钮来启动加法、减法、乘法和除法的相应操作。
A: <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
B: <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:Button ID="Button2" runat="server"
Text="A+B" OnClientClick="CallServerAdd(); return false;" />
<asp:Button ID="Button3" runat="server"
Text="A-B" OnClientClick="CallServerSub(); return false;" />
<asp:Button ID="Button4" runat="server"
Text="A*B" OnClientClick="CallServerMul(); return false;" />
<asp:Button ID="Button5" runat="server"
Text="A/B" OnClientClick="CallServerDiv(); return false;" />
现在,这些按钮中的每一个都调用一个服务器端方法来启动相应的服务器端函数。让我们看看 Add
函数的实现,其他函数将以相同的方式实现。
function CallServerAdd()
{
var a = document.getElementById('TextBox1').value;
var b = document.getElementById('TextBox2').value;
PageMethods.Add(a, b, OnResult,OnError);
}
在此函数中,我们所做的是提取文本框中的值,并将它们传递给名为 Add
的服务器端方法。第三个参数 OnResult
是方法调用成功时将调用的回调函数,第四个 OnError
是出现错误时将调用的函数。
function OnResult(result,userContext, method)
{
var resultMsg = "Result from Method [" + method +"] is: " + result;
alert(resultMsg);
}
function OnError(error, userContext, method)
{
if(error != null)
{
var resultMsg = "Error from Method [" + method +"] is: '" + error.get_message() + "'";
alert(resultMsg);
}
}
这些回调函数实际上可以告诉我们它们是从哪个方法调用的,即函数中的 method 参数。因此,我们可以为所有四个函数使用相同的回调函数并获取结果。我们将显示带有方法名称的结果,以便知道哪个方法正在产生结果或错误。
所以,我们也实现了其他三个函数。
function CallServerSub()
{
var a = document.getElementById('TextBox1').value;
var b = document.getElementById('TextBox2').value;
PageMethods.Sub(a, b, OnResult, OnError);
}
function CallServerMul()
{
var a = document.getElementById('TextBox1').value;
var b = document.getElementById('TextBox2').value;
PageMethods.Mul(a, b, OnResult, OnError);
}
function CallServerDiv()
{
var a = document.getElementById('TextBox1').value;
var b = document.getElementById('TextBox2').value;
PageMethods.Div(a, b, OnResult, OnError);
}
现在我们需要编写服务器端函数,这些函数接受两个输入参数,计算结果并返回结果。这些函数还可以抛出异常,这些异常将被我们的客户端错误回调函数处理。
[WebMethod]
public static string Add(string a, string b)
{
string result = "ERROR";
try
{
int ai = Convert.ToInt32(a);
int bi = Convert.ToInt32(b);
int res = ai+bi;
result = res.ToString();
}
catch
{
throw;
}
return result;
}
[WebMethod]
public static string Sub(string a, string b)
{
string result = "ERROR";
try
{
int ai = Convert.ToInt32(a);
int bi = Convert.ToInt32(b);
int res = ai - bi;
result = res.ToString();
}
catch
{
throw;
}
return result;
}
[WebMethod]
public static string Mul(string a, string b)
{
string result = "ERROR";
try
{
int ai = Convert.ToInt32(a);
int bi = Convert.ToInt32(b);
int res = ai * bi;
result = res.ToString();
}
catch
{
throw;
}
return result;
}
[WebMethod]
public static string Div(string a, string b)
{
string result = "ERROR";
try
{
int ai = Convert.ToInt32(a);
int bi = Convert.ToInt32(b);
int res = ai / bi;
result = res.ToString();
}
catch
{
throw;
}
return result;
}
注意:实现仅用于演示客户端-服务器通信。服务器端代码未以任何方式进行优化或重构。
现在,当我们运行应用程序时,我们可以看到结果如下
从服务器端向客户端传递和返回对象
现在我们已经看到了如何将数据从客户端传递到服务器端,以及从服务器端传递到客户端。本节特别讨论了使用 JSON
的可能性,以便如果我需要向客户端返回多个值,那么我可以将所有这些值封装在一个类中,将其序列化为 JSON
格式,然后将其返回给客户端。
让我们有一个简单的类,它封装了两个整数字段
[DataContract]
public class PairOfInts
{
int value1;
[DataMember]
public int Value1
{
get { return value1; }
set { value1 = value; }
}
int value2;
[DataMember]
public int Value2
{
get { return value2; }
set { value2 = value; }
}
public PairOfInts(int p1, int p2)
{
Value1 = p1;
Value2 = p2;
}
public static PairOfInts operator ++(PairOfInts p)
{
p.Value1 += 1;
p.Value2 += 1;
return p;
}
}
我们必须使用 DataContract
属性装饰/标记此类,以便它可以被序列化为 JSON
格式。需要在 JSON
格式中包含的成员必须是 public
并用 DataMember
属性装饰。
现在,让我们编写一个简单的服务器端函数,它创建该类型的对象并返回该对象的 JSON
表示 string
。
[WebMethod]
public static string GetSamplePairOfInts()
{
// Create a dummy pairofints object
PairOfInts pair = new PairOfInts(13, 17);
// Let us create a JSON serializer for it
DataContractJsonSerializer jsonMaker = new DataContractJsonSerializer(typeof(PairOfInts));
// USe a memory stream to hold the json converted data
using (MemoryStream ms = new MemoryStream())
{
// convert our class to json
jsonMaker.WriteObject(ms, pair);
ms.Flush();
// get the bytes of json representation of our class
byte[] bytes = ms.GetBuffer();
// return the json string to the client side caller
string jsonResult = Encoding.UTF8.GetString(bytes, 0, bytes.Length).Trim('\0');
return jsonResult;
}
}
现在从客户端,我们所需要做的就是调用此方法。处理成功的处理程序必须使用 eval
方法将此 JSON
字符串评估为 JavaScript 对象,然后将结果显示给用户。因此,让我们看看调用此方法、处理成功和处理错误的 JavaScript 代码。
function CallSamplePair()
{
PageMethods.GetSamplePairOfInts(OnJSONGetSuccess, OnJSONGetFailure);
}
function OnJSONGetSuccess(result, userContext, method)
{
if(result != null)
{
var PairOfInts = eval('('+ result + ')');
var resultMsg = "Pair from Method [" + method +"] is:
(" + PairOfInts.Value1 + ", " + PairOfInts.Value2 + ")";
alert(resultMsg);
}
}
function OnJSONGetFailure(error, userContext, method)
{
if(error != null)
{
var resultMsg = "Error from Method [" + method +"] is: '" + error.get_message() + "'";
alert(resultMsg);
}
}
现在,当我们调用此方法时,将在服务器端创建对象,并作为 JSON
返回给客户端。
此功能还可以扩展为从客户端获取一些值,在服务器上基于这些值创建一个对象,对该对象执行某些操作,然后以 JSON
格式返回更新后的对象。
为了看到这一点,让我们实现使用服务器端重载运算符来递增 pair
对象的逻辑。这将从客户端调用,并通过 JSON
显示结果。
服务器端方法如下
[WebMethod]
public static string IncrementPairOfInts(string val1, string val2)
{
// get the values from the user
int a = Convert.ToInt32(val1);
int b = Convert.ToInt32(val2);
// create a pair class
PairOfInts pair = new PairOfInts(a, b);
// increment the pair object
pair++;
// Let's create a JSON serializer for it
DataContractJsonSerializer jsonMaker =
new DataContractJsonSerializer(typeof(PairOfInts));
// Use a memory stream to hold the json converted data
using (MemoryStream ms = new MemoryStream())
{
// convert our class to json
jsonMaker.WriteObject(ms, pair);
ms.Flush();
// get the bytes of json representation of our class
byte[] bytes = ms.GetBuffer();
// return the json string to the client side caller
string jsonResult = Encoding.UTF8.GetString(bytes, 0, bytes.Length).Trim('\0');
return jsonResult;
}
}
客户端 JavaScript
function IncrementPair()
{
PageMethods.IncrementPairOfInts(document.getElementById('TextBox3').value,
document.getElementById('TextBox4').value,
OnJSONGetSuccess, OnJSONGetFailure);
}
function OnJSONGetSuccess(result, userContext, method)
{
if(result != null)
{
var PairOfInts = eval('('+ result + ')');
var resultMsg = "Pair from Method [" + method +"] is:
(" + PairOfInts.Value1 + ", " + PairOfInts.Value2 + ")";
alert(resultMsg);
}
}
function OnJSONGetFailure(error, userContext, method)
{
if(error != null)
{
var resultMsg = "Error from Method [" + method +"] is: '" +
error.get_message() + "'";
alert(resultMsg);
}
}
当我们运行它时,我们可以在客户端看到结果如下
从 JavaScript 调用 Web 服务
现在我们已经看到了如何调用简单的服务器端方法,如何调用带有某些值的服务器端方法,如何从服务器端获取返回值,以及如何以 JSON 格式获取多个返回值。
另一个重要的功能是能够从 JavaScript 调用 Web 服务。为了了解如何做到这一点,让我们创建一个简单的示例 Web 服务来执行加法。
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class TestService : System.Web.Services.WebService {
public TestService () {
}
[WebMethod]
public int Add(int x, int y) {
return x + y;
}
}
该服务使用 ScriptService
属性进行装饰/标记,以便可以从 JavaScript 调用它。
现在,为了能够从客户端调用此服务,我们需要在 ScriptManager
中添加对此服务的引用。可以这样做
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
<Services>
<asp:ServiceReference Path="TestService.asmx" />
</Services>
</asp:ScriptManager>
一旦我们将此服务添加到 ScriptManager
服务列表中,我们就可以像这样简单地调用此服务的方法
function InvokeService()
{
TestService.Add(document.getElementById('TextBox5').value,
document.getElementById('TextBox6').value,
OnServiceSuccess, OnserviceFailure, 'Webservice.Add');
}
function OnServiceSuccess(result, userContext, method)
{
var resultMsg = "Result from Method [" + userContext +"] is: " + result;
alert(resultMsg);
}
function OnserviceFailure(error, userContext, method)
{
if(error != null)
{
var resultMsg = "Error from Method [" + userContext +"] is: '" +
error.get_message() + "'";
alert(resultMsg);
}
}
上面的代码显示了调用服务的函数,即 InvokeService
。成功时将调用的回调函数,即 OnServiceSuccess
。以及发生错误时将调用的回调方法,即 OnserviceFailure
。现在让我们运行应用程序,看看如何从 JavaScript 调用此服务。
这里还有一点需要注意,我们使用了 userContext
在服务调用者和回调方法之间传递一些数据。如果我们需要将某些数据从调用方法传递到回调方法,userContext
就非常有用。由于回调可以为各种方法调用,甚至可以为同一方法多次调用,因此 userContext
可用于识别它们。
注意:下载示例代码并运行它将非常有帮助,因为本文档显示了 C#、JavaScript 和 ASPX 标记的代码片段。因此,要获得完整的图景,请参考示例代码。
看点
所以,我们已经看到了如何使用 ASP.NET Ajax 框架从 JavaScript 调用服务器端方法。我们也已经看到了如何从 JavaScript 使用 Web 服务。本文是从初学者的角度编写的。希望它有所启发。
历史
- 2013 年 1 月 10 日:初稿