2011-09-29 83 views
2

我已經知道,通過調用到Silverlight的WCF服務是異步。我也知道,很多人想方設法讓他們出於各種原因傻(阻塞例如UI線程)同步調用,這樣的事情應該避免像瘟疫,一般。Silverlight和同步調用WCF

我只是希望能夠處理所有的線程的東西我自己,因爲我已經發現具有掛鉤/脫鉤所有的「*已完成」的事件是很多額外的工作,和一個巨大的痛苦,尤其是當你不知道電話的順序等。任何人都知道一個聰明的方式來進行同步呼叫,並自己做線程?

+0

你爲什麼解開所有的「完成」事件? – ChrisF

+0

爲了避免內存泄漏。簡而言之,服務'A'可以在多個位置被調用,並且有時它的'Completed'事件沒有完全相同的處理程序。但是,讓我們避免設計/意圖討論,並堅持問題的技術部分.... –

+0

公平的,但知道設計/意圖可以影響解決方案。 – ChrisF

回答

3

既然你不應該同步網絡電話,你不應該做同步的網絡電話,你不應該做同步的網絡電話,如果你真的知道你在做什麼,那麼你實際上可以使僅當您不在UI線程中時纔會同步(阻止)調用。只是意識到它不是一個官方支持的場景(所以它不像其他功能那樣經過測試),但我已經嘗試了幾次,它只是起作用。

您只需要使用[ServiceContract]界面(而不是客戶端類) - 一個暴露開始/結束操作的界面 - 並且調用EndXXX(BeginXXX(parameters, null, null))(如下例所示)(這是一個帶有兩個控件的頁面,一個ButtonClick事件被綁定到Button_Click處理程序,一個名爲「txtDebug」 TextBox其中代碼寫入結果。

public partial class MainPage : UserControl 
{ 
    public MainPage() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     this.AddToDebug("In Button_Click"); 
     ThreadPool.QueueUserWorkItem(delegate 
     { 
      ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(); 
      ServiceReference1.Service1 asInterface = client; 
      this.AddToDebug("Calling server \"synchronously\"..."); 
      int result = asInterface.EndAdd(asInterface.BeginAdd(45, 67, null, null)); 
      this.AddToDebug("Result: {0}", result); 
      client.CloseAsync(); 
     }); 
    } 

    private void AddToDebug(string text, params object[] args) 
    { 
     if (args != null && args.Length > 0) 
     { 
      text = string.Format(text, args); 
     } 

     text = string.Format("[{0} - {1}] {2}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("HH:mm:ss.fff"), text); 

     this.Dispatcher.BeginInvoke(() => this.txtDebug.Text = this.txtDebug.Text + text + Environment.NewLine); 
    } 
} 

現在,如果你想從UI線程做,那麼真,沒有辦法阻止和等待響應(因爲響應也應該在UI線程上返回)。如果你conf可以使用開始/結束模式,您仍然可以執行異步調用,但不用擔心事件處理程序被泄露。

+0

是的,我永遠不想阻止UI線程,只是避免了'普通'Silverlight方法的開銷。這看起來像它會帶我走向正確的方向...... –

+0

你真的在Silverlight中試過這個嗎?由於Silverlight在IAsyncResult的實現上不支持AsyncWaitHandles,所以很難看出它是如何工作的?我並不是說它絕對不是我自己沒有嘗試過的,但如果它真的發生了,我真的很驚訝。 – AnthonyWJones

+0

是的,我在回覆之前嘗試過。正如我所說,它不被支持,但在簡單的情況下,我嘗試了它的工作,所以這是一個「使用風險自負」黑客攻擊。 – carlosfigueira

-1

如果換在另一個函數調用,而函數會睡覺,直到異步調用返回的是什麼?

+0

這基本上是我現在正在做的,但它仍然不能避免掛鉤/解除鉤住事件的代碼開銷。 –

1

解決方案依賴於阻塞線程(任何線程不只是UI線程),最好避免。線程是昂貴的資源,並且ThreadPool線程是有限的資源。這就是爲什麼網絡API首先具有回調語義。

我同意Carlos首先要做的是切換到服務提供的.NET異步模式接口,而不是基於可怕的事件。 (基於事件的方法旨在讓「事件思考」的UI開發人員變得簡單)。如果你的服務被稱爲「Service1」,你的客戶端類將被稱爲「Service1Client」。但是,該類還將支持名爲「Service1」的接口,該接口將具有OperationContracts的開始/結束版本。

「一個聰明的辦法,使同步調用」

沒有阻塞線程,這是不可能的。然而,使一系列同步任務不是真正的要求。我們要的只是是爲了確保一系列任務發生在序列。你可以簡單地通過從前一個任務的回調方法中調用下一個任務來完成這一任務,但是嵌套成爲一個問題。

看看這個系列的articles也許從.NET Asynchronous Pattern上的一個開始。不幸的是,WCF的一篇文章仍在進行中,但我很快就會發布它,這些內容經常會出現在這裏。