二、客戶端腳本直接訪問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" οnclick="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" οnclick="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