Azure Active Directory question
-
Hi all I have this method in a class which tries to get an access token from Azure Active Directory - it works if I use it in a Net Core app but hangs forever when I try to use it in a Winforms app
private async Task GetAccessToken()
{
// Utils.GetAppConfigSetting just reads keys in App.config
string Instance = Utils.GetAppConfigSetting("Instance");
string TenantID = Utils.GetAppConfigSetting("TenantID");
string ClientID = Utils.GetAppConfigSetting("ClientID");
string ClientSecret = Utils.GetAppConfigSetting("ClientSecret");
string BaseAddress = Utils.GetAppConfigSetting("BaseAddress");
string ResourceID = Utils.GetAppConfigSetting("ResourceID");
string APIServer = Utils.GetAppConfigSetting("APIServer");
string Authority = String.Format(CultureInfo.InvariantCulture,Instance, TenantID);this.App = ConfidentialClientApplicationBuilder.Create(ClientID) .WithClientSecret(ClientSecret) .WithAuthority(new Uri(Authority)) .Build(); this.ResourceIds = new string\[\] { ResourceID }; // this is where it hangs !! this.Result = await this.App.AcquireTokenForClient(this.ResourceIds).ExecuteAsync(); this.AccessToken = this.Result.AccessToken; // this.Client is a RestSharp client this.Client.Authenticator = new JwtAuthenticator(this.AccessToken); }
// I call it with this code
this.GetAccessToken().GetAwaiter().GetResult();
there is no error it just hangs - any ideas ? Edit It must be the UI thread in Winforms as I just tried the same code in a Console App and it worked perfectly
"We can't stop here - this is bat country" - Hunter S Thompson - RIP
-
Hi all I have this method in a class which tries to get an access token from Azure Active Directory - it works if I use it in a Net Core app but hangs forever when I try to use it in a Winforms app
private async Task GetAccessToken()
{
// Utils.GetAppConfigSetting just reads keys in App.config
string Instance = Utils.GetAppConfigSetting("Instance");
string TenantID = Utils.GetAppConfigSetting("TenantID");
string ClientID = Utils.GetAppConfigSetting("ClientID");
string ClientSecret = Utils.GetAppConfigSetting("ClientSecret");
string BaseAddress = Utils.GetAppConfigSetting("BaseAddress");
string ResourceID = Utils.GetAppConfigSetting("ResourceID");
string APIServer = Utils.GetAppConfigSetting("APIServer");
string Authority = String.Format(CultureInfo.InvariantCulture,Instance, TenantID);this.App = ConfidentialClientApplicationBuilder.Create(ClientID) .WithClientSecret(ClientSecret) .WithAuthority(new Uri(Authority)) .Build(); this.ResourceIds = new string\[\] { ResourceID }; // this is where it hangs !! this.Result = await this.App.AcquireTokenForClient(this.ResourceIds).ExecuteAsync(); this.AccessToken = this.Result.AccessToken; // this.Client is a RestSharp client this.Client.Authenticator = new JwtAuthenticator(this.AccessToken); }
// I call it with this code
this.GetAccessToken().GetAwaiter().GetResult();
there is no error it just hangs - any ideas ? Edit It must be the UI thread in Winforms as I just tried the same code in a Console App and it worked perfectly
"We can't stop here - this is bat country" - Hunter S Thompson - RIP
pkfox wrote:
It must be the UI thread in Winforms
Correct. Your
async
method tries to return to the current "execution context" after theawait
. In a WinForms app, when theasync
method was called from the UI thread, it tries to return to the UI thread. But you've blocked the UI thread by trying to execute theasync
method synchronously:this.GetAccessToken().GetAwaiter().GetResult(); // Blocks the UI thread
Therefore, the
async
method can never complete. If you're not accessing the UI from yourGetAccessToken
method, you can add.ConfigureAwait(false)
to yourExecuteAsync
call, so that the rest of the method can complete on a thread-pool thread:this.Result = await this.App.AcquireTokenForClient(this.ResourceIds).ExecuteAsync().ConfigureAwait(false);
Otherwise, you'll need to find a way to avoid blocking the UI thread. You'd need to make the calling method
async
. However, you want to avoidasync void
methods[^]. A simple solution is to move the code into a task-returningasync
method, and assign the returned task to a "discard" variable to avoid the compiler warning. Old code, don't use:private void ButtonClick(object sender, EventArgs e)
{
// Some code...
this.GetAccessToken().GetAwaiter().GetResult();
// Some more code...
}Bad fix, don't use:
private async void ButtonClick(object sender, EventArgs e)
{
// Some code...
await this.GetAccessToken();
// Some more code
}Better fix:
private void ButtonClick(object sender, EventArgs e)
{
_ = SomeMethodAsync();
}private async Task SomeMethodAsync()
{
// Some code...
await this.GetAccessToken();
// Some more code
}ConfigureAwait FAQ | .NET Blog[^]
"These people looked deep within my soul and as
-
pkfox wrote:
It must be the UI thread in Winforms
Correct. Your
async
method tries to return to the current "execution context" after theawait
. In a WinForms app, when theasync
method was called from the UI thread, it tries to return to the UI thread. But you've blocked the UI thread by trying to execute theasync
method synchronously:this.GetAccessToken().GetAwaiter().GetResult(); // Blocks the UI thread
Therefore, the
async
method can never complete. If you're not accessing the UI from yourGetAccessToken
method, you can add.ConfigureAwait(false)
to yourExecuteAsync
call, so that the rest of the method can complete on a thread-pool thread:this.Result = await this.App.AcquireTokenForClient(this.ResourceIds).ExecuteAsync().ConfigureAwait(false);
Otherwise, you'll need to find a way to avoid blocking the UI thread. You'd need to make the calling method
async
. However, you want to avoidasync void
methods[^]. A simple solution is to move the code into a task-returningasync
method, and assign the returned task to a "discard" variable to avoid the compiler warning. Old code, don't use:private void ButtonClick(object sender, EventArgs e)
{
// Some code...
this.GetAccessToken().GetAwaiter().GetResult();
// Some more code...
}Bad fix, don't use:
private async void ButtonClick(object sender, EventArgs e)
{
// Some code...
await this.GetAccessToken();
// Some more code
}Better fix:
private void ButtonClick(object sender, EventArgs e)
{
_ = SomeMethodAsync();
}private async Task SomeMethodAsync()
{
// Some code...
await this.GetAccessToken();
// Some more code
}ConfigureAwait FAQ | .NET Blog[^]
"These people looked deep within my soul and as
-
Thanks Richard should I leave the code as is in GetAccessToken() ? I got around it by using a BackGroundWorker but I think maybe your way is better
"We can't stop here - this is bat country" - Hunter S Thompson - RIP
If you're moving the code to a task-returning
async
method, and getting rid of the.GetAwaiter().GetResult()
call in favour ofawait
ing the operation, then theGetAccessToken
code should be fine.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
If you're moving the code to a task-returning
async
method, and getting rid of the.GetAwaiter().GetResult()
call in favour ofawait
ing the operation, then theGetAccessToken
code should be fine.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
How will I know when the job has finished ?
"We can't stop here - this is bat country" - Hunter S Thompson - RIP
That depends what you're trying to do. If you just want to run some code immediately after
GetAccessToken
has finished, you can put it in the newasync
method after theawait this.GetAccessToken();
line.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
That depends what you're trying to do. If you just want to run some code immediately after
GetAccessToken
has finished, you can put it in the newasync
method after theawait this.GetAccessToken();
line.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
pkfox wrote:
It must be the UI thread in Winforms
Correct. Your
async
method tries to return to the current "execution context" after theawait
. In a WinForms app, when theasync
method was called from the UI thread, it tries to return to the UI thread. But you've blocked the UI thread by trying to execute theasync
method synchronously:this.GetAccessToken().GetAwaiter().GetResult(); // Blocks the UI thread
Therefore, the
async
method can never complete. If you're not accessing the UI from yourGetAccessToken
method, you can add.ConfigureAwait(false)
to yourExecuteAsync
call, so that the rest of the method can complete on a thread-pool thread:this.Result = await this.App.AcquireTokenForClient(this.ResourceIds).ExecuteAsync().ConfigureAwait(false);
Otherwise, you'll need to find a way to avoid blocking the UI thread. You'd need to make the calling method
async
. However, you want to avoidasync void
methods[^]. A simple solution is to move the code into a task-returningasync
method, and assign the returned task to a "discard" variable to avoid the compiler warning. Old code, don't use:private void ButtonClick(object sender, EventArgs e)
{
// Some code...
this.GetAccessToken().GetAwaiter().GetResult();
// Some more code...
}Bad fix, don't use:
private async void ButtonClick(object sender, EventArgs e)
{
// Some code...
await this.GetAccessToken();
// Some more code
}Better fix:
private void ButtonClick(object sender, EventArgs e)
{
_ = SomeMethodAsync();
}private async Task SomeMethodAsync()
{
// Some code...
await this.GetAccessToken();
// Some more code
}ConfigureAwait FAQ | .NET Blog[^]
"These people looked deep within my soul and as
-
Except GetAccessToken() is in a separate class from the form
"We can't stop here - this is bat country" - Hunter S Thompson - RIP
That doesn't matter. You have a task-returning
async
method which calls it, and put any code you need to run after it's returned after theawait
. If you need to run code in the form after theasync
method in another class returns, you also use a task-returningasync
method, and put the code after theawait
.class SomeClass
{
private async Task GetAccessToken() { ... }public async Task DoSomething() { // Code to run in this class before getting the access token here... await GetAccessToken(); // Code to run in this class after getting the access token here... }
}
class YourForm
{
private SomeClass _someClass;private void FormLoad(object sender, EventArgs e) { \_someClass = new SomeClass(); \_ = DoSomethingInTheForm(); } private async Task DoSomethingInTheForm() { // Code to run in the form before getting the access token here... await \_someClass.DoSomething(); // Code to run in the form after getting the access token here... }
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
That doesn't matter. You have a task-returning
async
method which calls it, and put any code you need to run after it's returned after theawait
. If you need to run code in the form after theasync
method in another class returns, you also use a task-returningasync
method, and put the code after theawait
.class SomeClass
{
private async Task GetAccessToken() { ... }public async Task DoSomething() { // Code to run in this class before getting the access token here... await GetAccessToken(); // Code to run in this class after getting the access token here... }
}
class YourForm
{
private SomeClass _someClass;private void FormLoad(object sender, EventArgs e) { \_someClass = new SomeClass(); \_ = DoSomethingInTheForm(); } private async Task DoSomethingInTheForm() { // Code to run in the form before getting the access token here... await \_someClass.DoSomething(); // Code to run in the form after getting the access token here... }
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer