asp.net Js調用 WebService



ASP.Net AJAX(Atlas)終於集成到.Net Framework v3.5中了。使用方式和以往的很相識,只是名字空間稍微發生了改變。
本文將主要講解最基本最常見的用法。附件中有Sample代碼。

Sample 1: 調用WebService


建立一個WebService在站點目錄下,添加屬性ScriptService
using System.Web.Script.Services; // <-- 添加名字空間


namespace AjaxSample
{
   
/// <summary>
   
/// Summary description for Proxy
   
/// </summary>
    [WebService(Namespace = "http://www.ajaxsample.org/")]
    [WebServiceBinding(ConformsTo
= WsiProfiles.BasicProfile1_1)]
    [ToolboxItem(
false)]
    [ScriptService]
// <-- 添加此屬性
    public class Proxy : System.Web.Services.WebService
    {

        [WebMethod]
       
public int Add( int a, int b)
        {
           
return a + b;
        }
    }
}


在需要調用的頁面中添加ScriptManager,並添加對這個WebService的引用,使用相對路徑.
<asp:ScriptManager ID="ctlScriptManager" runat="server" >
   
<services>
       
<asp:servicereference Path="/Proxy.asmx" InlineScript="false" />
   
</services>
</asp:ScriptManager>


調用方式非常簡單,和以往一樣,名字空間.類名稱.方法名稱( 參數n, 回調函數)
<input type="button" value="異步調用 Add" onclick="OnBtnAddClicked()" />
<script language="javascript" type="text/javascript">
function OnBtnAddClicked()
{
    AjaxSample.Proxy.Add( 1, 2, OnAddCallback);
}

function OnAddCallback(result)
{
    alert(result);
}
</script>


注意:正式編碼的時候,請將JS放到頁面對應JS文件中,並注意方法命名。

最後得到的頁面就是:
    <form id="form1" runat="server">
   
<div>
       
<asp:ScriptManager ID="ctlScriptManager" runat="server" >
           
<services>
               
<asp:servicereference Path="/Proxy.asmx" InlineScript="true" />
           
</services>
       
</asp:ScriptManager>
       
       
<input type="button" value="異步調用 Add" onclick="OnBtnAddClicked()" />
       
<script language="javascript" type="text/javascript">
        function OnBtnAddClicked()
        {
            AjaxSample.Proxy.Add( 1, 2, OnAddCallback);
        }

        function OnAddCallback(result)
        {
            alert(result);
        }
       
</script>
   
       
<hr />
   
</div>
   
</form>





Sample 2: WebService返回XML類型的數據


在實際應用中,經常需要從WebService返回複合型數據,在客戶端通過XPath進行處理。下面講解如何做到處理XML類型的返回。

首先添加一個WebService方法返回XmlDocument類型,注意屬性的寫法,其中ResponseFormat= ResponseFormat.Xml指明瞭返回的數據類型,這個是必須的。
        [WebMethod]
        [ScriptMethod(ResponseFormat
= ResponseFormat.Xml, UseHttpGet=false)]
       
public XmlDocument GetXmlDoc()
        {
            XmlDocument doc
= new XmlDocument();
            doc.LoadXml(
@"<?xml version=""1.0""?>
<xmlRoot>
  <genericInfo>
    <content>1</content>
    <senderEmail>2</senderEmail>
  </genericInfo>
</xmlRoot>
");
           
return doc;
        }


在需要的頁面中同樣添加ScriptManager.,並添加對這個WebService的引用,使用相對路徑.
<asp:ScriptManager ID="ctlScriptManager" runat="server" >
   
<services>
       
<asp:servicereference Path="/Proxy.asmx" InlineScript="false" />
   
</services>
</asp:ScriptManager>


使用一個按鈕來觸發
<input type="button" value="Sampe 2:獲取XML類型的返回" onclick="OnBtnGetXmlClicked()" />
<script language="javascript" type="text/javascript">
function OnBtnGetXmlClicked()
{
    AjaxSample.Proxy.GetXmlDoc(OnGetXmlCallback);
}

function OnGetXmlCallback(result)
{
    alert(result.selectSingleNode("//xmlRoot/genericInfo/content/text()").nodeValue);
}
</script>


注意:正式的開發中,JS應該寫到頁面對應的JS文件中,且注意命名。
到這裏就結束了嗎?這個時候,用IE測試一切正常,但是使用Firefox,會出現錯誤。

 附件: 您所在的用戶組無法下載或查看附件

在頁面的*.cs文件中,加入Firefox的XPath查詢補丁,這樣就可以了。
using iVAS.Infrastructure;

namespace AjaxSample
{
   
public partial class InvokeWebService : PageBase
    {
       
protected void Page_Load(object sender, EventArgs e)
        {
            Javascript.IncludeJS(JavascriptFile.FirefoxXPath);
        }
    }
}



Sample 3: 調用頁面上的靜態方法

調用頁面上的靜態方法和調用WebService有很多相似之處。首先在頁面上放入ScriptManager控件,並指定EnablePageMethods屬性爲true

<asp:ScriptManager ID="ctlScriptManager" runat="server" EnablePageMethods="True" />


然後在*.cs文件中加入方法:
[WebMethod( EnableSession=true )]
public static int Add(int a, int b)
{
   
return a + b;
}


最後就可以在頁面中直接調用了,下面是全部頁面代碼:
<form id="form1" runat="server">
<div>
   
<asp:ScriptManager ID="ctlScriptManager" runat="server" EnablePageMethods="True" />
       
     
     
</div>
<input type="button" runat="server" id="btnInvoke" onclick="OnBtnInvokeClicked()" value="調用" />
<script language="javascript" type="text/javascript">
function OnBtnInvokeClicked()
{
    PageMethods.Add( 4, 3, OnAddCallback);
}

function OnAddCallback(result)
{
    alert(result);
}
</script>
</form>



Sample 4: 不刷新更新頁面內容
在很多情況下,需要不刷新頁面更新頁面的部分內容,那麼這就需要用到UpdatePanel了。有如下頁面代碼
<form id="form1" runat="server">
<div>
   
<asp:ScriptManager ID="ctlScriptManager" runat="server" />
   
<asp:UpdatePanel ID="ctlPanel" runat="server" RenderMode="Inline" UpdateMode="Conditional">
       
<ContentTemplate>
           
<asp:Label runat="server" ID="lblInfo"></asp:Label>
       
</ContentTemplate>
       
<Triggers>
           
<asp:AsyncPostBackTrigger ControlID="btnInvoke"/>
       
</Triggers>
   
</asp:UpdatePanel>
   
<hr/>
   
<asp:Button runat="server" ID="btnInvoke" Text="Get Time"
        onclick
="btnInvoke_Click" />
</div>
</form>


其中的按鈕btnInvoke觸發服務器事件btnInvoke_Click。服務器事件爲
protected void btnInvoke_Click(object sender, EventArgs e)
{
    lblInfo.Text
= DateTime.Now.ToLongTimeString();
}


運行Sample可以看到,點擊按鈕後,頁面在不刷新的情況下就能夠顯示當前時間。而服務端的寫法於平時無異,主要是ASP.Net標籤的寫法。




首先是ScriptManager,這在AJAX頁面中是必須的。然後是UpdatePanel標籤,這個標籤表示包括了刷新的部分。
RenderMode 表示UpdatePanel最終呈現的HTML元素。Block(默認)表示<div>,Inline表示<span>UpdateMode 更新模式,Always表示不管有沒有Trigger,其他控件都將更新該UpdatePanel, Conditional表示只有當前UpdatePanel的Trigger
ChildrenAsTriggers 當UpdateMode屬性爲Conditional時,UpdatePanel中的子控件的異步回送是否會引發UpdatePanle的更新。

            <Triggers>
               
<asp:AsyncPostBackTrigger ControlID="btnInvoke"/>
           
</Triggers>


這個標籤表示觸發異步揮發的條件,具體請看MSDN.可以設置ControlID爲服務器控件ID.或者設置EventName爲服務器事件名稱。


Sample 5: 在UpdatePanel更新前後加入JS代碼

經常地,需要在發送一個AJAX請求的時候,需要顯示一個進度動畫或者Loading...之類的文字,而在得到服務器返回後則做其它一些操作。那麼這就需要在客戶端中添加JS執行這些操作。

接着上一個例子的代碼來,在*.aspx文件中添加了如下代碼:
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(PageLodingHandler);
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(PageLoadedHandler);

// 初始化請求時調用,可以在此時取消請求或者檢測是否同時有其它請求
function InitializeRequestHandler(sender, args)
{
   
var prm = Sys.WebForms.PageRequestManager.getInstance();
   
   
var strMsg = "當前是否有未完成的請求 = " + prm.get_isInAsyncPostBack()
             
+ "/n當前請求的觸發控件ID = " + args.get_postBackElement().id
             
+ "/n/n是否繼續?點擊Cancel取消發送";
   
   
if( !window.confirm(strMsg) )
    {
       
// 取消當前請求
        args.set_cancel(true);
       
return;
    }
   
   
// 取消未完成的請求
    if( prm.get_isInAsyncPostBack() )
        prm.abortPostBack();
       
    document.getElementById(
"txtLog").innerText = "InitializeRequestHandler";
}

// 開始發送請求
function BeginRequestHandler(sender, args)
{
   
//var elem = args.get_postBackElement();
    document.getElementById("txtLog").innerText += "/r/nBeginRequestHandler";
}

// 得到請求響應並已經更新了頁面
function EndRequestHandler(sender, args)
{
    document.getElementById(
"txtLog").innerText += "/r/nEndRequestHandler";
}

// 得到響應並且更新了頁面,(注意,不管同步還是異步都會觸發這個)
function PageLodingHandler(sender, args)
{
    document.getElementById(
"txtLog").innerText += "/r/PageLodingHandler";
}

// 得到響應還沒有更新頁面
function PageLoadedHandler(sender, args)
{
    document.getElementById(
"txtLog").innerText += "/r/PageLoadedHandler";
}


這5個掛鉤分別是可選了,也就是說你只需要掛接自己需要的。這裏只是做爲範例所以全部例舉出來了

initializeRequest:
在該事件的處理函數中,我們可以進行一些額外的、在將請求發送回服務器端之前的附加任務,例如取消即將發出的異步請求、修改某個將要發送回服務器的參數信息、檢測當前是否有重複的請求等

beginRequest:異步請求即將發送時觸發的事件,在該事件的處理函數中,我們可以顯示出某段提示更新的信息(UpdateProgress控件)。

pageLoding:異步請求正在進行時觸發的事件,在該事件的處理函數中,我們可以爲UpdatePanel即將到來的更新進行一些準備,例如釋放使用過的資源等。同樣在該事件的處理函數中我們還可以及檢查服務器端發送過來的狀態信息,並根據不同的狀態完成相應的操作控制。

pageLoaded:異步請求返回時觸發的事件,在該事件的處理函數中,我們可以訪問到更新完成後UpdatePanel中新的內容。

endRequest:異步請求完成時觸發的事件,在該事件的處理函數中,我們可以顯示更新中可能遇到的異常信息、隱藏UpdateProgress控件、或是其他一些什麼別的附加操作等。



Sampe 6: 在母版頁及內容頁中使用AJAX

在母版頁和內容頁中使用AJAX唯一的不同是ScriptManager。在母版頁中放入ScriptManager,而內容頁放入ScriptManagerProxy就可以了。下面是母版頁代碼:
<html xmlns="http://www.w3.org/1999/xhtml"; >
<head runat="server">
   
<title>在母版頁中使用AJAX</title>
   
<asp:ContentPlaceHolder ID="cpHead" runat="server">
   
</asp:ContentPlaceHolder>
</head>
<body>
   
<form id="form1" runat="server">
   
<div>
       
<asp:ScriptManager ID="ctlScriptManager" runat="server"
            EnablePageMethods
="True" />
       
<asp:ContentPlaceHolder ID="cpMain" runat="server">
       
</asp:ContentPlaceHolder>
   
</div>
   
</form>
</body>
</html>


以下是內容頁的代碼
<asp:Content ID="Content1" ContentPlaceHolderID="cpHead" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="cpMain" runat="server">
   
<asp:ScriptManagerProxy ID="ctlScriptManagerProxy" runat="server">    
    
   
</asp:ScriptManagerProxy>
   
<input type="button" runat="server" id="btnInvoke" onclick="OnBtnInvokeClicked()" value="調用" />
   
<script language="javascript" type="text/javascript">
    function OnBtnInvokeClicked()
    {
        PageMethods.Add( 4, 3, OnAddCallback);
    }
   
    function OnAddCallback(result)
    {
        alert(result);
    }
   
</script>
</asp:Content>


調用方式和其它是一樣的




PS:
這些都只是最基本的用法,到這裏,基本能夠應付大部分的開發了。
Atlas中還有對於ProgressBar、Timer的封裝,如果需要,請自行參閱相關文檔

需要注意的幾個問題:
1.跨域之間的AJAX調用一般很少,如果很比較,可以使用Mash-UP,橋接技術。本質上就是HTTP請求的轉發
2.對於Drag & Drop,MS也提供了很多種方便的方法,可以自己google
3.UpdatePanel中間儘量少用第3放控件,因爲根據MSDN的說法,放如UpdatePanel中間的控件必須符合很多要求,如Response.Write PreRender之類,所以MS不能保證任何控件都能夠做到。
Jerry.Wang 最後編輯於 2008-07-14 11:16:59
 
 
補充:直接使用異步提交,不更新頁面

        protected void Page_Load(object sender, EventArgs e)
        {
            ScriptManager.GetCurrent(
this).RegisterAsyncPostBackControl(btnSubmit);
        }

       
protected void btnSubmit_Click(object sender, EventArgs e)
        {
           
//............
        }


btnSubmit是按鈕
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章