As a result of my question about TaskCompletionSource
I tried a similar technique for getting the tokens
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;
}
calling this using
var task1 = GetOAuthTokens();
_oAuthKeyService.OAuthResponse = task1.Result;
However the program locks up when I run it.
The following works OK
var oauthService = new OAuthService(_configurationCloud);
var code = OAuthLogin.GetAuthorizationCode(_configurationCloud); // causes a login dialog
var tokens = oauthService.GetTokens(code);
_oAuthKeyService.OAuthResponse = tokens;
and brings up the authorisation dialog box.
When I answered your previous question I assumed you had a requirement to use a TaskCompletionSource object so I am sorry if this has sent you in the wrong direction. As Paulo has said you don't normally need to use TaskCompletionSource with async/await code but you do need to understand a bit more how to use it.
Calling Result on a Task will cause that thread to block, now in a non-UI thread this isn't such an issue (just not ideal) but in a UI thread this will effectively stop your UI from responding until the task has completed, assuming it just doesn't stop completely due to a deadlock.
The thing is to learn how to use async/await in a UI environment because to get it to work you have too use async/await everywhere otherwise you will end up trying to use Task.Result to access your data and get a blocked UI thread for your troubles.
This is a good starter guide - https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Now I assume you are pulling the code
from the page like this (cobbled from code samples on GitHub) and then fetching the tokens.
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;
}
}
however your code is blocking on the .Result
What you need to do is use async/await all the way up however when you use await it complains about the lack of async on the method, so, just add it; yes this is allowed and there are many articles and blog posts about this that catch people new to async/await in winforms/wpf UI.
e.g.
// 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;
}
}
I've uploaded the code as gist I hope it helps