0

由于我对 TaskCompletionSource的问题

我尝试了一种类似的技术来获取令牌

private t.Task<OAuthTokens> GetOAuthTokens()
    {
        var tcs = new t.TaskCompletionSource<OAuthTokens>();
        t.Task.Run(
            async () =>
            {
                var oauthService = new OAuthService(_configurationCloud);
                var code = OAuthLogin.GetAuthorizationCode(_configurationCloud);
                var response = await oauthService.GetTokensAsync(code);

                tcs.SetResult(response);
            });
        return tcs.Task;
    }

使用

var task1 = GetOAuthTokens();
_oAuthKeyService.OAuthResponse = task1.Result;

但是,当我运行它时程序会锁定。

以下工作正常

        var oauthService = new OAuthService(_configurationCloud);
        var code = OAuthLogin.GetAuthorizationCode(_configurationCloud);  // causes a login dialog
        var tokens = oauthService.GetTokens(code);
        _oAuthKeyService.OAuthResponse = tokens;

并弹出授权对话框。

4

1 回答 1

4

当我回答你之前的问题时,我假设你需要使用 TaskCompletionSource 对象,所以如果这让你走错了方向,我很抱歉。正如Paulo所说,您通常不需要将 TaskCompletionSource 与 async/await 代码一起使用,但您确实需要更多地了解如何使用它。

在任务上调用Result将导致该线程阻塞,现在在非 UI 线程中这不是这样的问题(只是不理想),但在 UI 线程中,这将有效地阻止您的UI 响应,直到任务完成,假设它只是由于死锁而没有完全停止。

问题是要学习如何在 UI 环境中使用 async/await,因为要让它工作,你必须在任何地方都使用 async/await,否则你最终会尝试使用 Task.Result 来访问你的数据并获得阻塞的 UI 线程为你的烦恼。

这是一个很好的入门指南 - https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

现在我假设您正在像这样从页面中提取(从 GitHub 上的代码示例code拼凑而成),然后获取令牌。

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var content = webBrowser1.DocumentText;
    var regex = new Regex(@"\<title\>(.+?)=(.+?)\</title\>");
    var match = regex.Match(content);
    if (!match.Success || match.Groups.Count != 3)
        return;

    switch (match.Groups[1].Value.ToLowerInvariant())
    {
        case "code": // we have a code
            var code = match.Groups[2].Value;
            var config = new ApiConfiguration(Configuration.ClientId, Configuration.ClientSecret, Configuration.RedirectUrl);
            var service = new OAuthService(config, new WebRequestFactory(config));
            var tokens = service.GetTokensAsync(code).Result; // <= blocking
            _keyService.OAuthResponse = tokens;
            break;

        case "error": // user probably said "no thanks"
            webBrowser1.Navigate(_logoffUri);
            break;
    }
} 

但是您的代码在.Result

您需要做的是一直使用 async/await ,但是当您使用 await 时,它会抱怨该方法缺少异步,所以,只需添加它;是的,这是允许的,并且有许多关于此的文章和博客文章吸引了新的 async/await在 winforms/wpf UI 中的人。

例如

// we add async to the callback - yup it's allowed 
private async void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    var content = webBrowser1.DocumentText;
    var regex = new Regex(@"\<title\>(.+?)=(.+?)\</title\>");
    var match = regex.Match(content);
    if (!match.Success || match.Groups.Count != 3)
        return;

    switch (match.Groups[1].Value.ToLowerInvariant())
    {
        case "code": // we have a code
            var code = match.Groups[2].Value;
            var config = new ApiConfiguration(Configuration.ClientId, Configuration.ClientSecret, Configuration.RedirectUrl);
            var service = new OAuthService(config, new WebRequestFactory(config));
            var tokens = await service.GetTokensAsync(code); // <= now we can use await here => non-blocking
            _keyService.OAuthResponse = tokens;
            break;

        case "error": // user probably said "no thanks"
            webBrowser1.Navigate(_logoffUri);
            break;
    }
} 

我已将代码作为要点上传,希望对您有所帮助

于 2015-09-04T23:49:40.697 回答