Silverlight中通過Javascript的XmlHttp調用伺服器端內容的同步與非同步問題

來源:互聯網
上載者:User

  在做Silverlight開發時,經常需要以調用WebService的形式與伺服器端進行互動。例如在Silverlight嵌入到SharePoint的項目中,常需要Silverlight調用SharePoint的WebService來與SharePoint交換資訊。如果直接在Silverlight中通過C#的webclient訪問WebService將涉及許可權問題,需要將'clientaccesspolicy.xml'部署到伺服器上對應的位置(參考《 Silverlight 2beta2 調用 SharePoint的WebService......》),所以一般採用javascript的方式用xmlhttp向伺服器發送請求。

  javascript的XmlHttp發送請求時有兩種方式:同步發送和非同步發送。如果採用同步發送的方式,xmlhttp.send會阻塞整個線程,導致包括Silverlight在內的頁面處於停滯等待狀態,直到xmlhttp得到伺服器端的反饋。而採用非同步發送的方式,則可避免線程被阻塞。

  這裡我們用一個簡單的例子來說明這個問題(樣本在Silverlight 2.0 RTM環境下調試通過,原始碼可在這裡下載)。

  在Silverlight的Page.xmal頁面上放置兩個按鈕分別同步和非同步擷取伺服器端ServerSimulationPage.aspx頁面的內容。為類比實際環境,在ServerSimulationPage.aspx頁面載入時調用了一個sleep函數延時3秒,並且返回的頁面內容包含了瞬時時間以便查看頁面內容是否更新過。我們期望在使用者點擊按鈕時就顯示一個提示使用者等待的資訊,直到成功得到伺服器端的頁面內容後再關閉提示使用者等待的資訊。

  當點“Get Page Content from Server(Sync Mode)”按鈕時,Silverlight調用Javascript函數getPageContentSync:

 

C#語言: 同步方式按鈕的Click事件// 同步方式擷取
private void btnGetPageContentSync_Click(object sender, RoutedEventArgs e)
{
     OpenTipInfo();

     // 調用Javascript 以便利用XmlHttp 同步擷取伺服器端資料
     object objReturn = HtmlPage.Window.Invoke("getPageContentSync", "ServerSimulationPage.aspx");
     if (objReturn != null)
         GetPageContentSuccess(objReturn.ToString());
}

 

JavaScript語言: Javascript同步方式擷取伺服器內容的代碼// 以“同步”方式從伺服器擷取頁面內容
        function getPageContentSync(url) {
            var xmlhttp = getXmlHttp();
            if (xmlhttp) {
                xmlhttp.open("GET", url, false);     //false表示同步調用,會阻塞進程,導致頁面等待,即提示資訊不及時顯示出來
                xmlhttp.send();
                return xmlhttp.responseText;         //同步調用,可以返回結果。這裡最好要判斷一下返回的狀態 xmlhttp.status
            }
        }

 

  由於xmlhttp.open的最後一個參數是false,表示xmlhttp以同步的方式向伺服器發送請求。當xmlhttp.send()運行後,線程就在此等待,直到伺服器端運行完畢並返回結果給xmlhttp,然後再將xmlhttp.responseText的內容返回給Silverlight。這個過程中雖然在Silverlight中運行“  object objReturn = HtmlPage.Window.Invoke("getPageContentSync", "ServerSimulationPage.aspx"); ” 之前已經OpenTipInfo() 了,但由於線程被xmlhttp.send阻塞,所以整個過程使用者感覺在擷取到ServerSimulationPage.aspx頁面內容之前Silverlight頁面一直停滯在那裡,並且似乎看不到任何提示使用者等待的資訊。

 

  但如果採用非同步方式則能解決這一問題。當點擊按鈕“Get Page Content from Server(Async Mode)”時,響應Silverlight事件:

 

C#語言: 非同步方式按鈕的Click事件// 非同步方式擷取
        private void btnGetPageContentAsync_Click(object sender, RoutedEventArgs e)
        {
            OpenTipInfo();

            // 調用Javascript 以便利用XmlHttp 非同步擷取伺服器端資料
            HtmlPage.Window.Invoke("getPageContentAsync", "ServerSimulationPage.aspx");
        }

 

  該事件中,首先OpenTipInfo()顯示提示使用者等待資訊,然後調用javascript函數getPageContentAsync,但在運行“HtmlPage.Window.Invoke("getPageContentAsync", "ServerSimulationPage.aspx");”時並不期待其立即返回結果。在javascript的getPageContentAsync函數裡非同步方式擷取伺服器端頁面內容:

 

JavaScript語言: Javascript非同步方式擷取伺服器內容的代碼// 以“非同步”方式擷取伺服器端頁面內容
        function getPageContentAsync(url) {
            var xmlhttp = getXmlHttp();
            if (xmlhttp) {
                xmlhttp.onreadystatechange = function() { doStateChange.apply(xmlhttp) }    //當返回狀態改變時,通知函數doStateChange
                xmlhttp.open("GET", url, true);     //true表示非同步呼叫,false表示同步調用。如果為false,則會阻塞進程,導致頁面等待,即提示資訊不及時顯示出來
                xmlhttp.send();
            }
        }

        // 當XmlHttp的返回狀態改變時,進行相應處理
        function doStateChange()
        {
            if (this.readyState == 4)
            {
                if (this.status == 200)     //調用成功,正確獲得了返回資訊
                {
                    var ctl = document.getElementById("silverlightControl");
                    if (ctl)
                        ctl.content.Page.GetPageContentSuccess(this.responseText);
                }
                else                        //調用失敗,未返回正確的頁面資訊
                {                   
                    var ctl = document.getElementById("silverlightControl");
                    if (ctl)
                        ctl.content.Page.GetPageContentFailed();
                }
            }
        }

 

  這裡函數getPageContentAsync中同樣利用xmlhttp向伺服器發送請求,但是以非同步方式發送請求“xmlhttp.open("GET", url, true);  ”,並且xmlhttp.send()後並不期望馬上得到返回結果,所以getPageContentAsync函數沒有返回任何值。但在我們監聽了xmlhttp.onreadystatechange事件:

                        xmlhttp.onreadystatechange = function() { doStateChange.apply(xmlhttp) } 

  當xmlhttp接收到伺服器端的反饋時就立即通知doStateChange函數,在doStateChange函數裡我們可以判斷是否伺服器端已經運行完畢並返回了正確結果。當得知已經成功擷取伺服器端的頁面內容後,就立即調用Silverlight裡的相應事件,通知Silverlight做相應處理;如果得知擷取伺服器端內容失敗,也要立即通知Silverlight做相應處理。

  這裡涉及到Javascript調用Silverlight的函數的問題,所以在Silverlight裡必須暴露出相應的函數供Javascript調用:

 

C#語言: Silverlight暴露函數給Javascript調用// 擷取頁面內容成功 此方法暴露給Javascript調用
        [ScriptableMember]
        public void GetPageContentSuccess( string pageContent)
        {
            txtContent.Text = pageContent;
            CloseTipInfo();
            HtmlPage.Window.Alert("Get page content successfully!");
        }

        // 擷取頁面內容失敗 此方法暴露給Javascript調用
        [ScriptableMember]
        public void GetPageContentFailed()
        {
            CloseTipInfo();
            HtmlPage.Window.Alert("SORRY! Get page content failed!");
        }

  當然,xmlhttp調用其它的WebService也是類似原理。

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.