2010-01-19 25 views
0

我創建一個Silverlight應用程序,我有一對夫婦與自動生成的代理問題(通過將在Visual Studio 2008中添加服務引用)是否有一個事件可以告訴WCF自動生成的代理何時執行異步操作?

在客戶端上生成代理的異步方法生成和我可以打電話給他們,那很好。

但我真正想做的是在我的頁面上有一個'忙'或'異步加載'動畫。我過去通過使用一個靜態類來存儲目前正在進行的異步調用的數量,實現了這一點 - 這種方法的問題在於,我必須記住每當我調用異步方法時手動遞增和遞減計數代理(並在完成時遞減) - 當然,我會忘記經常這樣做。

我試過的其他方法稍微好一點就是將代理包裝在我自己的包裝類中,所以不是調用代理上的方法,而是調用包裝器上的方法,包裝器會增加/減少計數 - This有點好一些,但是當我的服務的操作合同/名稱/參數不斷變化時,它證明是有點痛苦的。當服務在早期發展。

我錯過了什麼嗎?因爲我真的認爲它應該比我目前的方法簡單一些。

+0

不是開箱即用的,但是當您調用BeginXXXX並將其設置回來時,設置一個小布爾標誌會相當容易,那麼輸入EndXXX回調,不是嗎? – 2010-01-19 22:14:17

回答

0

我同意,應該有一些比你目前的方法更容易。但是,除非我們可以使用T4模板來生成代理類,否則,除非你想推出自己的(不推薦IMO,YMMV),否則按照你已經嘗試過的方式來看,你認爲最好的方法就是拍攝。

我目前正在使用這兩種方法的混合。我已經將所有WCF調用包裝在一系列數據訪問類中,這些類將MS提供的不太有用的事件驅動模型轉換爲更簡單的回調方法。在這些數據訪問類中,我還使用一個靜態的PreProcessCall()方法來封裝每個調用,該方法處理增加未完成的調用計數器並將調用編組到後臺線程;我用靜態的PostProcessCall()方法封裝了每個返回調用,該方法遞減未完成的調用計數器並將回調編組到UI線程中。

public static void PreProcessCall(Action action) 
    { 
     Logger.LogDebugMessage("Pre-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name); 
     Interlocked.Increment(ref pendingCalls); 
     ThreadPool.QueueUserWorkItem(o => 
      { 
       try 
       { 
        action(); 
       } 
       catch (System.Exception ex) 
       { 
        DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message); 
        UpdatePendingCalls(); 
       } 
      }); 
    } 

    private static void UpdatePendingCalls() 
    { 
     Interlocked.Decrement(ref pendingCalls); 
     Debug.Assert(pendingCalls >= 0, "The number of pending calls should never go below zero."); 
     if (pendingCalls <= 0) 
     { 
      lock (pendingCallNotifications) 
      { 
       while (pendingCallNotifications.Count > 0) 
       { 
        Action callback = pendingCallNotifications.Dequeue(); 
        Globals.Dispatcher.BeginInvoke(callback); 
       } 
      } 
     } 
    } 

    public static void PostProcessCall(Action action) 
    { 
     Logger.LogDebugMessage("Post-processing call for {0}", (new StackTrace()).GetFrame(1).GetMethod().Name); 
     UpdatePendingCalls(); 
     Globals.Dispatcher.BeginInvoke(() => 
      { 
       try 
       { 
        action(); 
       } 
       catch (System.Exception ex) 
       { 
        DataPublisher.GetPublisher().RaiseDataProcessExceptionOccurred(ex, ex.Message); 
       } 
      }); 
    } 

因此,一個典型的調用看起來是這樣的:

public void SendMessage(string message, OperationCallback callback) 
    { 
     DataConnectionManager.PreProcessCall(() => 
      { 
       Logger.LogDebugMessage("SendChatMessage"); 
       notificationClient.SendChatMessageAsync(roomViewModel.SessionId, message, callback); 
      }); 
    } 

    void RoomService_SendChatMessageCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) 
    { 
     OperationCallback callback = (OperationCallback)e.UserState; 
     DataConnectionManager.PostProcessCall(() => 
      { 
       if (callback != null) 
       { 
        callback(e.Error); 
       } 
       Logger.LogDebugMessage("SendChatMessageCompleted."); 
      }); 
    } 

就像我說的,基本上你已經嘗試過。

0

我創建了一個方法只是在最近,解決了這個問題 參見:Dynamic IL method causes "Operation could destabilize the runtime"

基本上,創建一個包裝調用您的異步方法,並讓這種包裝採用動態方法和反思註冊一個通用的事件。那麼你永遠不用擔心在包裝器中爲每個異步調用維護包裝器。

相關問題