2015-07-28 44 views
2

我做了一些工作的OAuth,在這裏我得到我的刷新令牌通過提供異步API方法(GetRefreshTokenAsync):獲取異步結果死鎖(儘管設置配置等​​待爲false)

public async Task<Tokens> RenewAuthentication() 
{ 
    AppTokenResult token = await OAuth.GetRefreshTokenAsync("clientid", 
     "clientsecret", 
    @"myRefreshToken"); 

    string accessToken = token.AccessToken; 
    string refreshToken = token.RefreshToken; 

    return new Tokens(accessToken, refreshToken); 

} 

如果我把這個就像從一個非異步方法,例如:

public void noAsync() 
{ 
    var r = RenewAuthentication(); 
    var x = r.Result; 
} 

它鎖死應用程序:(如果我刪除第二行(r.Result),那麼它的工作原理,但是這是廢話,因爲我無法獲得。結果我試着讀

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

但通過向GetRefreshTokenAsync()方法添加.ConfigureAwait(false)方法嘗試其方法1之後,它沒有任何區別。

有什麼建議嗎?

+0

所以UI應該工作而結果從沒有收到? – Thulur

+0

這是在什麼平臺上運行?控制檯,WPF,iOS,ASP.NET ...?你爲什麼要從同步方法調用異步方法?建議使用從頭到尾的異步。 – Krumelur

+0

在收到結果時,UI可以工作或不工作。雖然我寧願屏蔽用戶界面,但這不是真正的問題,對吧?問題是整個事情都陷入僵局。 在WinForms上運行。我從窗體加載調用異步。當表單首次加載時,我想讓用戶使用OAuth,以便我可以存儲它們的令牌。 – Prof

回答

5

它鎖死應用程序:(

這是在具有自定義同步將做一個環境的async方法是什麼阻擋。

如果調用此的「FormLoad」,你請不要在需要阻止只要選中你的事件處理程序async這樣你就可以await上的操作:

public Form() 
{ 
    this.Load += OnLoadHandler; 
} 

public async void OnLoadHandler(object sender, EventArgs e) 
{ 
    var result = await RenewAuthenticationAsync(); 
    // Store the result here 
} 
+0

是的,這將工作,但我很幸運能夠參加我可以添加異步限定詞的事件。如果我想從主函數調用它,會發生什麼? – Prof

+0

你可以調用一個異步方法方法「fire and forget way」。您必須擺脫阻止異步操作的想法。 – Krumelur

+0

然後你會被擰緊。 'async'往往會在你的應用程序中增長並擁有自己的代碼庫。你不能自然地混合同步和異步方法,這是行不通的。唯一的選擇是'async void',這很糟糕,絕對不能使用。你可以設計你的應用程序,以便它可以解決這個問題。如果不能,你可以使用同步API。如果你正在尋找可擴展性,做'async'將會主要受益。如果這不是問題,同步也可以。 –

1

如果您訪問任務的結果屬性,它將作爲一個Future,它會阻塞當前線程,直到任務與結果返回。

我不認爲你實際上得到一個僵局,但你在等待永遠不會完成任務。

確保您的來電OAuth.GetRefreshTokenAsync回報。

+0

它會返回,如果我刪除.Result。如果我在RenewAuthentication中的字符串賦值處斷點,那麼當我不使用.Result()時它們會被命中。當我添加.Result時,GetRefreshTokenAsync永遠不會返回(完成)。我能做什麼? – Prof

+0

當然,你是對的。對於GetRefreshTokenAsync的調用顯然是由等待任務結果的同一個線程等待的。所以確實,你是對的......一個僵局。 要解決此問題,您必須在單獨的任務中等待任務的結果。所以,如果你更換 '變種X = r.Result' 通過 'Task.Run(()=> {VAR X = r.Result; //做一些與X這裏 });' 一切都應該工作如預期。 – Norbert

-1

async代碼是一路構造。你不能做半個異步,不應該試圖強制它。在這裏,noAsync似乎沒有任何用處。

在他的智慧,克利裏先生明確指出,每個async方法都有其自己的上下文中,它可以在用戶界面上運行延續。

你可以肯定地說OAuth.GetRefreshTokenAsync是使用ConfigureAwait(false)內部?如果沒有,你會陷入僵局。

+0

我不能確定GetFreshTokenAsync內部使用ConfigureAwait(false) – Prof

+0

我設法抓住源代碼。它不使用ConfigureAwait(false),但是如果我在公開的RenewAuthenatication()後粘貼.ConfigureAwait,它不會死鎖(儘管它不是很有用,因爲我無法提取任務結果) – Prof

1

您需要確保RenewAuthentication的結果沒有編組回到UI線程。 ConfigureAwait(false)是非常正是爲了這樣一個目的:

var renewAwaitable = RenewAuthentication().ConfigureAwait(false); 
var result = renewAwaitable.GetAwaiter().GetResult(); 

不過,我會用全力開展與異步,而不是建議。沒有任何理由阻止UI應用程序中的任何地方 - 只需禁用在等待令牌返回時不得使用的任何控件,並在啓用它時啓用它們。

+1

結束了所有的異步。 – Prof