二、客户端脚本直接访问Web Service
借助于asp.net ajax异步通信层自动生成的客户端代理,我们也可以在客户端JS中使用与服务器端同样的语法调用定义在服务器端的Web Service的方法!下面我们分两种情况来分析:
1、客户端直接调用本地Web Service
默认情况下,asp.net Web Service并没有提供直接通过客户端脚本进行访问的方式,为了实现这个功能,我们必须借助于asp.net ajax框架,它为我们提供了使用JS直接调用本地Web Service完善的支持,所以对于以下的操作,你必须确保已安装了asp.net ajax框架。下面让我们看看具体如何实现:
(1)、新建一个asp.net ajax Web站点,然后添加一个Web Service
下面是修改后的Web Service代码:
<%@ WebService Language="C#" Class="WebService" %> using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; [WebService(Namespace = "http://ruihua.cnblogs.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.Web.Script.Services.ScriptService] public class WebService : System.Web.Services.WebService { [WebMethod] public string Hello(string name) { return string.Format("Hello,{0}!Current Time is :{1}", name, DateTime.Now.ToString()); } }
请注意红色部分,要想使客户端能够访问到Web Service,我们必须为类添加ScriptService特性(当然,你也可以直接添加到相应的方法上)。这个特性是在asp.net ajax框架的Extension部分定义的。好了,Web Service就已经写好了,下面看看如何在客户端调用。
b、新建一个asp.net ajax站点,修改后的前台代码如下所示:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> <script type="text/javascript"> function pageLoad(sender,args) { //注意引用方式 WebService.Hello("Ruihua",onCompleted); } //异步调用后执行的回调函数 function onCompleted(result) { $get("result").innerHTML = result; } </script> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="http://localhost/WebServiceForJS/WebService.asmx" /> </Services> </asp:ScriptManager> <div id="result"></div> </form> </body> </html>
代码非常简单,我们只需在ScriptManager中添加对Web Service文件的引用,然后在客户端脚本中使用[NameSpace].[ClassName].[MethodName][para1,para2,...,callbackFunction]的方式直接调用即可,然后在回调函数中接收值并进一步处理。(注意,测试过程中,请将站点都设置为Web共享,这样在引用Web Service的时候就不必考虑到端口号,因为对于同域内不同端口的访问JS也是不可以的)。如果一切顺利,你将看到如下结果:(注意游览地址)
以上是在客户端访问本地Web Service的情况,下面让我们看看客户端如何访问远程Web Service.
2、客户端访问远程Web Service
出于安全性考虑,客户端JS脚本是不可以直接访问远程Web Service的,若想实现这个功能,则必须在本地服务器端提供一个代理,透过这个代理进行访问。下面我们以访问http://www.webxml.com.cn/WebServices/WeatherWebService.asmx为例来说明。具体可采取以下两种方式:
a、通过本地Web Service中转
实现思路:服务器端建立一个Web Service,然后在相应的方法中调用远程Web Service的方法,客户端脚本直接访问本地Web Service中方法。
主要代码:
<%@ WebService Language="C#" Class="WebService" %> using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; [WebService(Namespace = "http://ruihua.cnblogs.com/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.Web.Script.Services.ScriptService] public class WebService : System.Web.Services.WebService { [WebMethod] public string[] GetWeatherbyCityName(string theCityName) { WeatherForcast.WeatherWebService ws = new WeatherForcast.WeatherWebService(); return ws.getWeatherbyCityName(theCityName); } }
前台Default.aspx代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> <script type="text/javascript"> function btnGetWeather_onclick(sender,args) { var cityName=$get("tbCityName").value; WebService.GetWeatherbyCityName(cityName,onCompleted,onFailed); } //异步调用后成功后执行的回调函数 function onCompleted(result) { var str = new Sys.StringBuilder(); for(var i=0;i<result.length;i++) { str.append(result[i]); str.append("<br/>"); } $get("result").innerHTML = str.toString(); } //异步调用后失败后执行的回调函数 function onFailed(error) { $get("result").innerHTML = error.get_message(); } </script> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="WebService.asmx" /> </Services> </asp:ScriptManager> <label id="lblCityName">Please input CityName:</label> <input id="tbCityName" type="text" /> <input id="btnGetWeather" type="button" value="Get Weather" onclick="return btnGetWeather_onclick()" /> <div id="result"></div> </form> </body> </html>
运行结果:
下载本示例
http://files.cnblogs.com/ruihua/webserviceforjs1.rar
b、使用Web Service Bridge
asp.net ajax中Web Service桥的支持位于Futures CTP版本中,所以在使用之前,必须保证计算机安装了asp.net ajax 的Futures CTP版本。
在网站的Bridges目录下新建一个WeatherForcase.asbx的XML文件,内容如下:
<?xml version="1.0" encoding="utf-8" ?> <bridge namespace="Ruihua" className="WeatherForcast"> <proxy type="Microsoft.Web.Preview.Services.BridgeRestProxy" serviceUrl="http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName"/> <method name="getWeatherbyCityName"> <input> <parameter name="theCityName"/> </input> </method> </bridge>
我们来看一下.asbx文件各标签:
(1)<Bridge/>:定义该本地代理的命名空间(namespace属性)和类名(className属性)。这两个属性是代表客户端调用时使用的命名空间及类名,与远程Web Service我关。
(2)<proxy/>:声明该代理的类型,并指定远程Web Service的URL属性。注意这里的URL属性值的构成:.asmx文件的URL加斜杆和要调用的方法名。
(3)<method/>:定义了远程Web Service中要调用的方法名称及参数,注意name属性应与远程Web Service中要调用的方法名称一致。
(4)该标签中通过<parameter/>子标签声明了方法的参数。
有几点需要特别说明一下:
(1)、我在实际使用过程中发现,web Service桥只支持httpGet协议,所以我们需要在Web.config文件中开启HttpGet方式(默认为HttpPost)。在<configuration/><system.web/>下添加如下配置:
<webServices> <protocols> <add name="HttpGet"/> </protocols> </webServices>
(2)如果你使用Futures CTP版本自带的模板新建了一个支持Web Service桥的站点,你需要手动将<buildProviders>节下的<add>元素的extension属性中的"*"号去掉,这是Fetures CTP的Bug。
(3)一个Web Service桥文件中仅能代理一个方法,如果你需要访问多个方法,则需要新建多个Web Service桥。如你在其中写了多个<proxy>及<method/>,客户端调用时也只会执行最先的那个代理对应的方法。暂时没还没找到其它好的方法。
(4)不能使用asp.net ajax异步通信层的服务器端至客户端的类型转换功能,因此我们在客户端得到的返回类型只能是string类型,从而加大了进一步进行处理的难度。
由于存在以上限制,个人感觉使用web Service桥不如使用本地Web Service中转方便,或许是asp.net ajax在这方面还不够成熟吧!
下面是Default.aspx的内容:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> <script type="text/javascript"> function btnGetWeather_onclick(sender,args) { var cityName=$get("tbCityName").value; Ruihua.WeatherForcast.getWeatherbyCityName({"theCityName":cityName},onCompleted,onFailed); } //异步调用后成功后执行的回调函数 function onCompleted(result) { $get("result").innerHTML = result; } //异步调用后失败后执行的回调函数 function onFailed(error) { $get("result").innerHTML = error.get_message(); } </script> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="Bridges/WeatherForcase.asbx" /> </Services> </asp:ScriptManager> <label id="lblCityName">Please input CityName:</label> <input id="tbCityName" type="text" /> <input id="btnGetWeather" type="button" value="Get Weather" onclick="return btnGetWeather_onclick()" /> <div id="result"></div> </form> </body> </html>
以上有两点需要特别注意:
(1)调用远程Web方法的参数的书写方式是采用JSON方式,各个参数需要显式指明参数名和值,并包装为一个JS对象整体传入本地代理方法,这与常规调用方式有所不同。
(2)在ScriptManager中添加的是对Web Service桥文件的引用。
在城市名称中输入"深圳",下面是运行结果:
下载本示例
http://files.cnblogs.com/ruihua/usewebservicebridge.rar