2016-06-08 59 views
1

我有一個有趣的問題..我有一個登錄方法工作的WCF服務。C#TaskCompletionSource無法正常工作

我創建了一個taskcompletion並等待結果出現。

好的問題是,如果我調用2次登錄方法,第二個不返回任何東西。我把中斷點,它進入完成的事件,它調用trysetresult,但沒有回報。

這裏是我的代碼

public Task<User> LoginByUserName(string userName, string password) 
    { 
     var tcs = new TaskCompletionSource<User>(); 

     if (!_registeredEventList.Contains ("LoginByUserNameCompleted")) { 
      _registeredEventList.Add ("LoginByUserNameCompleted"); 


      userService.LoginByUserNameCompleted += (object sender, LoginByUserNameCompletedEventArgs args) => { 
       if (args.Error != null) 
        tcs.TrySetException (args.Error); 
       if (args.Result != null) 
        tcs.TrySetResult (args.Result); 
       else 
        tcs.TrySetResult (null); 

      }; 

     } 

     userService.LoginByUserNameAsync (userName,password); 
     return tcs.Task; 
    } 

我把這樣的;

var loginResult= await Task.Run(()=>serviceHelper.LoginByUserName(userName,password)); 

例如,如果用戶一次輸入錯誤的登錄信息,則在第二次嘗試中,不會返回任何內容。

PS:_registeredEventList在事件已訂閱或未訂閱時保留。如果是,那麼它不會再創造。當我刪除該部分時,它可以工作。

+2

如果你的事件已經被註冊了,你基本上只返回不做任何事的Task(不使用tcs變量)。 – Evk

+0

@Evk,謝謝你的回覆,但我不知道如何解決它? – unbalanced

+0

很難說只給出了代碼,但想到的一件事是將所有TaskCompletionSource存儲在列表(字段)中,並在LoginByUserNameCompleted觸發時 - 設置_all_任務完成源的結果。 – Evk

回答

1

由於Evk評論說,問題是您的代碼有一個條件,它永遠不會返回完成的任務。具體來說,第一次調用此代碼時,它將添加一個條目到_registeredEventList(這可能永遠不會被刪除)。所有稍後的調用將返回從未完成的Taskwhich is a major no-no in asynchronous programming

若要退訂作爲回調的一部分解決這個問題,我建議您修改EAP包裝:

public static Task<User> LoginByUserNameTaskAsync(this UserService @this, string userName, string password) 
{ 
    var tcs = new TaskCompletionSource<User>(); 
    LoginByUserNameCompletedDelegate callback = null; 
    callback = (object sender, LoginByUserNameCompletedEventArgs args) => 
    { 
    @this.LoginByUserNameCompleted -= callback; 
    if (args.Error != null) 
     tcs.TrySetException(args.Error); 
    else 
     tcs.TrySetResult(args.Result); 
    }; 
    @this.LoginByUserNameCompleted += callback; 

    @this.LoginByUserNameAsync(userName, password); 
    return tcs.Task; 
} 

(我也使它的擴展方法,把它follow the TAP naming parameters for TAP-over-EAP wrappers)。