I'm trying to authenticate users to an app using AWS Cognito.
This this my login method:
[RelayCommand]
private async Task Login()
{
AmazonCognitoIdentityProviderClient provider =
new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());
CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);
InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
{
Password = "userPassword"
};
try
{
AuthFlowResponse authResponse = await use.StartWithSrpAuthAsync(authRequest);
if (authResponse.AuthenticationResult != null)
{
accessToken = authResponse.AuthenticationResult.AccessToken;
await Shell.Current.GoToAsync($"//{nameof(MainPage)}");
}
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Error", "Incorrect Credentials", "Exit");
}
}
In AWS documentation they instead use:
AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
Testing my code code with .ConfigureAwait(false), it would break whenever i tried to change the UI, either with await Shell.Current.GoToAsync($"//{nameof(MainPage)}"); or await Shell.Current.DisplayAlert("Error", "Incorrect Credentials", "Exit");, with the exception The application called an interface that was marshalled for a different thread.
I read the following document, https://devblogs.microsoft.com/dotnet/configureawait-faq/, and though I understand what it means generally, I don't really understand what it will mean to my code if I remove it.
Thanks for your help.
ConfigureAwait(true) is the default behavior; it means "resume on the captured context". The "captured context" is technically SynchronizationContext.Current or TaskScheduler.Current, but for most modern code that usually means "UI context" or "no context" (i.e., thread pool context).
ConfigureAwait(false) does not resume on the captured context, so it always uses "no context" (i.e., thread pool context). This is generally recommended for libraries but not applications. And these days there's more of a movement away from using it even for libraries.
By using the default (ConfigureAwait(true)), your code was resuming execution on the UI thread, so it was calling Shell.Current.* on the UI thread, which is the correct behavior.
By using ConfigureAwait(false), your code is resuming on a thread pool thread, so it is calling Shell.Current.* on a thread pool thread, and gets the error The application called an interface that was marshalled for a different thread.
I don't really understand what it will mean to my code if I remove it.
It means that your await will resume on the UI thread, which is exactly what it needs to do. So it is correct to remove it.
Again, the guidance has always been ConfigureAwait(false) for libraries and not ConfigureAwait(false) for applications; and these days using ConfigureAwait(false) at all is becoming less common.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With