Call async method synchronously with await

483 Views Asked by At

I'm calling an async method (LoginAsync) for Authorization.

 UserObject = clienAuthenticationService.LoginAsync(sUser).Result;
 if (UserObject != null)
 {
    // Proceed for further code;
 }
 else
 {
    // Show Error message of failed authentication;
 }

As this is third party service, I need output of LoginAsync before I go to next line (If block). Current code is working fine for me and I know it waits until LoginAsync is executed.

However, I'm getting recommendation to Replace this use of 'Task.Result' with 'await'.

Question : I'm not sure if my case is relevant for await, since I need kind of Synchronous execution of async method. Can someone please confirm if recommendation given to me is irrelevant in my case or there is way to call async method synchronously with await ?

EDIT : After comments, I modified my code to add await instead of .Result. Still, unable to read response from async method. Below is new code

public static async Task<bool> CallJimService(LoginUserClass sUser)
{

    var result = clientJIMServiceCall.LoginAsync(sUser).ConfigureAwait(false);
  
    LoginUserClass loginUserDetails = await result;

    if (loginUserDetails != null && loginUserDetails.UserProperties != null && loginUserDetails.UserProperties.LoggedIn)
    {
        return true;
    }
    else
    {
        return false;
    }
  
 }
 
 
 
  public static Boolean ValidateUserCredentails(string pstrUserName, string pstrPassWord)
  {
        LoginUserClass sUser = new LoginUserClass();
        sUser.UserName = pstrUserName;
        sUser.Password = pstrPassWord;
        
        return CallJimService(sUser).Result; // Here I want to avoid using .Result.
  }

Also, I don't want to change ValidateUserCredentails() to async. How Can I get through this?

2

There are 2 best solutions below

0
ArwynFr On

The LoginAsync method is marked async, and returns a Task. This method is expected to have an asynchronous implementation. You cannot execute this method synchronously, because this method does not have a synchronous implementation. If the class you are using would provide a synchronous implementation of the Login operation, they would have to expose a Login method.

There is no guarantee that calling this method asynchronously will result in an asynchronous operation. Asynchronous methods may return synchronously if the state needs them to. For instance, AsyncLogin may return synchronously if you already have logged in. However, unless doing something extremely specific, there must be at least one execution path in the method that requires some asynchronous operation.

Recommendation given to you is not irrelevant.

You should not block on an async operation, especially using Task.Result. Asynchronous operations does not involve multithreading, and awaiting on a Task.Result may provoke a deadlock of your application, because your thread will be waiting on the Result and will not be able to respond to the async operation signaling completion.

You'd rather await the LoginAsync method asynchronously, making your method async as well.

If you are forced to call the LoginAsync method from a synchronous context, the correct implementation will depend on what exactly you are trying to achieve and what the LoginAsync method does.

0
Harsh On

If you are able to use await (that is if you are in an async method already), then use await.

UserObject = await clienAuthenticationService.LoginAsync(sUser);

Using await helps the code run synchronous(that is it preserves flow of control). I will try to explain async usage through the following example, which has asynchronous execution flow, but synchronous control flow - Following code runs out of sync (asynchronous that is) -

// Authenticate the user, but don't wait here while authenticating.
// Async part could be - Checking database for user details. (Network IO operation)
var UserAuthTask = LoginAsync();

// Prepare a layout or something to show when authentication fails. Don't show yet.
// Again, don't wait while preparing.
// Async part could be -  Reading a render template file. (File IO operation)
var AuthFailScreen = PrepareFailScreenAsync();

// Similar to failure screen.
var AuthSuccessScreen = PrepareSuccessScreenAsync();

Now, we use await to synchronize the flow to our liking -

var UserAuthResult = await UserAuthTask;
if (UserAuthResult.Success)
{
    var SuccessScreen = await AuthSuccessScreen;
    SuccessScreen.Show();
}
else
{
    var FailScreen = await AuthFailScreen;
    FailScreen.Show();
}

You could await each of the tasks before, like var UserAuthTask = await LoginAsync();, but then you would lose the benefit of doing multiple things which could've been done while authenticating. I am not sure about exception handling, but mix and match of async and sync code will likely cause issues.

Please correct me if I am wrong at any point. Thanks.