C# MYOB oauthService.GetTokenAsync不显示对话框

C# MYOB oauthService.GetTokenAsync不显示对话框,c#,oauth,async-await,myob,taskcompletionsource,C#,Oauth,Async Await,Myob,Taskcompletionsource,由于我的问题 我尝试了一种类似的技术来获得代币 private t.Task<OAuthTokens> GetOAuthTokens() { var tcs = new t.TaskCompletionSource<OAuthTokens>(); t.Task.Run( async () => { var oauthService = new OA

由于我的问题

我尝试了一种类似的技术来获得代币

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 oauthService = new OAuthService(_configurationCloud);
        var code = OAuthLogin.GetAuthorizationCode(_configurationCloud);  // causes a login dialog
        var tokens = oauthService.GetTokens(code);
        _oAuthKeyService.OAuthResponse = tokens;
并打开授权对话框。

当我回答您的问题时,我假设您需要使用TaskCompletionSource对象,因此如果这让您走错了方向,我很抱歉。如前所述,您通常不需要将TaskCompletionSource与异步/等待代码一起使用,但您确实需要进一步了解如何使用它

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

关键是要学习如何在UI环境中使用async/await,因为要让它正常工作,您必须在任何地方都使用async/await,否则您将尝试使用Task.Result访问数据,并获得阻塞的UI线程以解决问题

这是一个很好的入门指南-

现在我假设您像这样从页面中提取
code
(从GitHub上拼凑而成),然后提取令牌

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;
    }
} 
当我回答您的问题时,我认为您有使用TaskCompletionSource对象的要求,因此如果这让您走错了方向,我很抱歉。如前所述,您通常不需要将TaskCompletionSource与异步/等待代码一起使用,但您确实需要进一步了解如何使用它

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

关键是要学习如何在UI环境中使用async/await,因为要让它正常工作,您必须在任何地方都使用async/await,否则您将尝试使用Task.Result访问数据,并获得阻塞的UI线程以解决问题

这是一个很好的入门指南-

现在我假设您像这样从页面中提取
code
(从GitHub上拼凑而成),然后提取令牌

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;
    }
} 

我希望这会有帮助

@shaun_a_wilde你能帮忙吗?什么用户界面?如果它是基于消息泵的,比如WinForms或WPF,那么它将被阻塞。为什么要使用
Task.Run
TaskCompletionSource
调用已经异步的代码?我编辑了这个问题,以澄清锁定的是程序,而不是UI。(我必须按Ctrl-Alt-Delete键才能结束程序)。我正在使用Task.Run和TaskCompletionSource以等待任务运行。有一个同步选项。GetTokens,但我正在试验。你能显示调用代码吗?它是一个事件处理程序吗?我在“使用@shaun_a_wilde调用它”的问题中包含了它。你能帮忙吗?什么UI?如果它是基于消息泵的,比如WinForms或WPF,那么它将被阻塞。为什么要使用
Task.Run
TaskCompletionSource
调用已经异步的代码?我编辑了这个问题,以澄清锁定的是程序,而不是UI。(我必须按Ctrl-Alt-Delete键才能结束程序)。我正在使用Task.Run和TaskCompletionSource以等待任务运行。有一个同步选项。GetTokens,但我正在试验。你能显示调用代码吗?它是一个事件处理程序吗?我把它包含在“使用调用”下的问题中,谢谢Shaun。我得到以下块:var tokens=service.GetTokensAsync(code.Result);我知道我可以使用service.GetTokens()代替,这也会阻塞。我不明白的是,为什么登录对话框只在我使用service.GetTokens()时出现。当我使用Async选项时,程序将锁定,并且从不解锁。这就好像登录对话框是不可见的。@kirsteng-提供的小片段很难说-GetTokens实现在github上实际上使用了一种不依赖于async/await模式的替代异步方法-因此它可以用于没有async/await的框架版本,例如.NET2。谢谢Shaun,我现在将使用非异步版本的GetTokens()。谢谢Shaun。我得到以下块:var tokens=service.GetTokensAsync(code.Result);我知道我可以使用service.GetTokens()代替,这也会阻塞。我不明白的是,为什么登录对话框只在我使用service.GetTokens()时出现。当我使用Async选项时,程序将锁定,并且从不解锁。这就好像登录对话框是不可见的。@kirsteng-提供的小片段很难说-GetTokens实现在github上实际上使用了一种不依赖于async/await模式的替代异步方法-因此它可以用于没有async/await的框架版本,例如.NET2。谢谢Shaun,我现在将使用非异步版本的GetTokens()。
// 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;
    }
}