二、客户端脚本直接访问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
单击显示全图,Ctrl+滚轮缩放图片


下面是修改后的Web Service代码:
Save.jpg保存

<%&#64; WebService Language&#61;"C#" Class&#61;"WebService" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace &#61; "http://ruihua.cnblogs.com/")]
[WebServiceBinding(ConformsTo &#61; 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());}
}


请注意红色部分&#xff0c;要想使客户端能够访问到Web Service&#xff0c;我们必须为类添加ScriptService特性&#xff08;当然&#xff0c;你也可以直接添加到相应的方法上&#xff09;。这个特性是在asp.net ajax框架的Extension部分定义的。好了&#xff0c;Web Service就已经写好了&#xff0c;下面看看如何在客户端调用。

b、新建一个asp.net ajax站点&#xff0c;修改后的前台代码如下所示&#xff1a;
Save.jpg保存

<%&#64; Page Language&#61;"C#" AutoEventWireup&#61;"true" CodeFile&#61;"Default.aspx.cs" Inherits&#61;"_Default" %>

<html xmlns&#61;"http://www.w3.org/1999/xhtml">
<head runat&#61;"server"><title>Untitled Pagetitle><script type&#61;"text/Javascript">
function pageLoad(sender,args){//注意引用方式
WebService.Hello("Ruihua",onCompleted);}//异步调用后执行的回调函数
function onCompleted(result){$get("result").innerHTML &#61; result;}
script>
head>
<body><form id&#61;"form1" runat&#61;"server"><asp:ScriptManager ID&#61;"ScriptManager1" runat&#61;"server"><Services><asp:ServiceReference Path&#61;"http://localhost/WebServiceForJS/WebService.asmx" />Services>asp:ScriptManager><div id&#61;"result">div>form>
body>
html>


代码非常简单&#xff0c;我们只需在ScriptManager中添加对Web Service文件的引用&#xff0c;然后在客户端脚本中使用[NameSpace].[ClassName].[MethodName][para1,para2,...,callbackFunction]的方式直接调用即可&#xff0c;然后在回调函数中接收值并进一步处理。&#xff08;注意&#xff0c;测试过程中&#xff0c;请将站点都设置为Web共享&#xff0c;这样在引用Web Service的时候就不必考虑到端口号&#xff0c;因为对于同域内不同端口的访问JS也是不可以的&#xff09;。如果一切顺利&#xff0c;你将看到如下结果&#xff1a;(注意游览地址&#xff09;
单击显示全图&#xff0c;Ctrl&#43;滚轮缩放图片


以上是在客户端访问本地Web Service的情况&#xff0c;下面让我们看看客户端如何访问远程Web Service.


2、客户端访问远程Web Service

出于安全性考虑&#xff0c;客户端JS脚本是不可以直接访问远程Web Service的&#xff0c;若想实现这个功能&#xff0c;则必须在本地服务器端提供一个代理&#xff0c;透过这个代理进行访问。下面我们以访问[url]http://www.webxml.com.cn/WebServices/WeatherWebService.asmx[/url]为例来说明。具体可采取以下两种方式:

a、通过本地Web Service中转

实现思路&#xff1a;服务器端建立一个Web Service&#xff0c;然后在相应的方法中调用远程Web Service的方法&#xff0c;客户端脚本直接访问本地Web Service中方法。

主要代码&#xff1a;
Save.jpg保存

<%&#64; WebService Language&#61;"C#" Class&#61;"WebService" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace &#61; "http://ruihua.cnblogs.com/")]
[WebServiceBinding(ConformsTo &#61; WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {[WebMethod]public string[] GetWeatherbyCityName(string theCityName){WeatherForcast.WeatherWebService ws &#61; new WeatherForcast.WeatherWebService();return ws.getWeatherbyCityName(theCityName);}
}


前台Default.aspx代码&#xff1a;
Save.jpg保存

<%&#64; Page Language&#61;"C#" AutoEventWireup&#61;"true" CodeFile&#61;"Default.aspx.cs" Inherits&#61;"_Default" %>

<html xmlns&#61;"http://www.w3.org/1999/xhtml">
<head runat&#61;"server"><title>Untitled Pagetitle><script type&#61;"text/Javascript">
function btnGetWeather_ {var cityName&#61;$get("tbCityName").value;WebService.GetWeatherbyCityName(cityName,onCompleted,onFailed);}//异步调用后成功后执行的回调函数
function onCompleted(result){var str &#61; new Sys.StringBuilder();for(var i&#61;0;i"
"
);}$get("result").innerHTML &#61; str.toString();}//异步调用后失败后执行的回调函数
function onFailed(error){$get("result").innerHTML &#61; error.get_message();}
script>
head>
<body><form id&#61;"form1" runat&#61;"server"><asp:ScriptManager ID&#61;"ScriptManager1" runat&#61;"server"><Services><asp:ServiceReference Path&#61;"WebService.asmx" />Services>asp:ScriptManager><label id&#61;"lblCityName">Please input CityName&#xff1a;label><input id&#61;"tbCityName" type&#61;"text" /><input id&#61;"btnGetWeather" type&#61;"button" value&#61;"Get Weather" οnclick&#61;"return btnGetWeather_onclick()" /><div id&#61;"result">div>form>
body>
html>


运行结果&#xff1a;
单击显示全图&#xff0c;Ctrl&#43;滚轮缩放图片


下载本示例  
[url]http://files.cnblogs.com/ruihua/webserviceforjs1.rar[/url]

b、使用Web Service Bridge

asp.net ajax中Web Service桥的支持位于Futures CTP版本中&#xff0c;所以在使用之前&#xff0c;必须保证计算机安装了asp.net ajax 的Futures CTP版本。
单击显示全图&#xff0c;Ctrl&#43;滚轮缩放图片


在网站的Bridges目录下新建一个WeatherForcase.asbx的XML文件&#xff0c;内容如下&#xff1a;
Save.jpg保存

xml version&#61;"1.0" encoding&#61;"utf-8" ?>
<bridge namespace&#61;"Ruihua" className&#61;"WeatherForcast"><proxy type&#61;"Microsoft.Web.Preview.Services.BridgeRestProxy" serviceUrl&#61;"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName"/><method name&#61;"getWeatherbyCityName"><input><parameter name&#61;"theCityName"/>input>method>
bridge>


我们来看一下.asbx文件各标签&#xff1a;
(1)&#xff1a;定义该本地代理的命名空间(namespace属性&#xff09;和类名&#xff08;className属性&#xff09;。这两个属性是代表客户端调用时使用的命名空间及类名&#xff0c;与远程Web Service我关。
&#xff08;2&#xff09;&#xff1a;声明该代理的类型&#xff0c;并指定远程Web Service的URL属性。注意这里的URL属性值的构成&#xff1a;.asmx文件的URL加斜杆和要调用的方法名。
(3):定义了远程Web Service中要调用的方法名称及参数&#xff0c;注意name属性应与远程Web Service中要调用的方法名称一致。
(4)该标签中通过子标签声明了方法的参数。

有几点需要特别说明一下&#xff1a;
&#xff08;1&#xff09;、我在实际使用过程中发现&#xff0c;web Service桥只支持httpGet协议&#xff0c;所以我们需要在Web.config文件中开启HttpGet方式&#xff08;默认为HttpPost&#xff09;。在下添加如下配置&#xff1a;
Save.jpg保存

<webServices><protocols><add name&#61;"HttpGet"/>protocols>webServices>


&#xff08;2&#xff09;如果你使用Futures CTP版本自带的模板新建了一个支持Web Service桥的站点&#xff0c;你需要手动将节下的元素的extension属性中的"*"号去掉&#xff0c;这是Fetures CTP的Bug。
(3)一个Web Service桥文件中仅能代理一个方法&#xff0c;如果你需要访问多个方法&#xff0c;则需要新建多个Web Service桥。如你在其中写了多个&#xff0c;客户端调用时也只会执行最先的那个代理对应的方法。暂时没还没找到其它好的方法。
(4)不能使用asp.net ajax异步通信层的服务器端至客户端的类型转换功能&#xff0c;因此我们在客户端得到的返回类型只能是string类型&#xff0c;从而加大了进一步进行处理的难度。

由于存在以上限制&#xff0c;个人感觉使用web Service桥不如使用本地Web Service中转方便&#xff0c;或许是asp.net ajax在这方面还不够成熟吧&#xff01;

下面是Default.aspx的内容&#xff1a;
Save.jpg保存

<%&#64; Page Language&#61;"C#" AutoEventWireup&#61;"true" CodeFile&#61;"Default.aspx.cs" Inherits&#61;"_Default" %>

<html xmlns&#61;"http://www.w3.org/1999/xhtml">
<head runat&#61;"server"><title>Untitled Pagetitle><script type&#61;"text/Javascript">
function btnGetWeather_ {var cityName&#61;$get("tbCityName").value;Ruihua.WeatherForcast.getWeatherbyCityName({"theCityName":cityName},onCompleted,onFailed);}//异步调用后成功后执行的回调函数
function onCompleted(result){$get("result").innerHTML &#61; result;}//异步调用后失败后执行的回调函数
function onFailed(error){$get("result").innerHTML &#61; error.get_message();}
script>
head>
<body><form id&#61;"form1" runat&#61;"server"><asp:ScriptManager ID&#61;"ScriptManager1" runat&#61;"server"><Services><asp:ServiceReference Path&#61;"Bridges/WeatherForcase.asbx" />Services>asp:ScriptManager><label id&#61;"lblCityName">Please input CityName&#xff1a;label><input id&#61;"tbCityName" type&#61;"text" /><input id&#61;"btnGetWeather" type&#61;"button" value&#61;"Get Weather" οnclick&#61;"return btnGetWeather_onclick()" /><div id&#61;"result">div>form>
body>
html>


以上有两点需要特别注意&#xff1a;
&#xff08;1&#xff09;调用远程Web方法的参数的书写方式是采用JSON方式&#xff0c;各个参数需要显式指明参数名和值&#xff0c;并包装为一个JS对象整体传入本地代理方法&#xff0c;这与常规调用方式有所不同。
(2)在ScriptManager中添加的是对Web Service桥文件的引用。

在城市名称中输入"深圳"&#xff0c;下面是运行结果&#xff1a;
单击显示全图&#xff0c;Ctrl&#43;滚轮缩放图片


下载本示例
[url]http://files.cnblogs.com/ruihua/usewebservicebridge.rar[/url]