1

I've been working on a project and saw the below code. I am new to the async/await world. As far as I know, only a single task is performing in the method then why it is decorated with async/await. What benefits I am getting by using async/await and what is the drawback if I remove async/await i.e make it synchronous I am a little bit confused so any help will be appreciated.

[Route("UpdatePersonalInformation")]
public async Task<DataTransferObject<bool>> UpdatePersonalInformation([FromBody] UserPersonalInformationRequestModel model)
{
    DataTransferObject<bool> transfer = new DataTransferObject<bool>();
    try
    {
        
        model.UserId = UserIdentity;

        transfer = await _userService.UpdateUserPersonalInformation(model);

    }
    catch (Exception ex)
    {
        transfer.TransactionStatusCode = 500;
        transfer.ErrorMessage = ex.Message;
    }
    return transfer;
}

Service code

public async Task<DataTransferObject<bool>> UpdateUserPersonalInformation(UserPersonalInformationRequestModel model)
{

    DataTransferObject<bool> transfer = new DataTransferObject<bool>();
    await Task.Run(() =>
    {
        try
        {
            var data = _userProfileRepository.FindBy(x => x.AspNetUserId == model.UserId)?.FirstOrDefault();
            if (data != null)
            {
                var userProfile = mapper.Map<UserProfile>(model);
                userProfile.UpdatedBy = model.UserId;
                userProfile.UpdateOn = DateTime.UtcNow;
                userProfile.CreatedBy = data.CreatedBy;
                userProfile.CreatedOn = data.CreatedOn;
                userProfile.Id = data.Id;
                userProfile.TypeId = data.TypeId;
                userProfile.AspNetUserId = data.AspNetUserId;
                userProfile.ProfileStatus = data.ProfileStatus;
                userProfile.MemberSince = DateTime.UtcNow;
                if(userProfile.DOB==DateTime.MinValue)
                {
                    userProfile.DOB = null;
                }
                _userProfileRepository.Update(userProfile);

               

                transfer.Value = true;
            }
            else
            {
                transfer.Value = false;
                transfer.Message = "Invalid User";
            }

        }
        catch (Exception ex)
        {

            transfer.ErrorMessage = ex.Message;
        }

    });
    
    return transfer;
}
2

5 Answers 5

2

What benefits I am getting by using async/await

Normally, on ASP.NET, the benefit of async is that your server is more scalable - i.e., can handle more requests than it otherwise could. The "Synchronous vs. Asynchronous Request Handling" section of this article goes into more detail, but the short explanation is that async/await frees up a thread so that it can handle other requests while the asynchronous work is being done.

However, in this specific case, that's not actually what's going on. Using async/await in ASP.NET is good and proper, but using Task.Run on ASP.NET is not. Because what happens with Task.Run is that another thread is used to run the delegate within UpdateUserPersonalInformation. So this isn't asynchronous; it's just synchronous code running on a background thread. UpdateUserPersonalInformation will take another thread pool thread to run its synchronous repository call and then yield the request thread by using await. So it's just doing a thread switch for no benefit at all.

A proper implementation would make the repository asynchronous first, and then UpdateUserPersonalInformation can be implemented without Task.Run at all:

public async Task<DataTransferObject<bool>> UpdateUserPersonalInformation(UserPersonalInformationRequestModel model)
{
  DataTransferObject<bool> transfer = new DataTransferObject<bool>();
  try
  {
    var data = _userProfileRepository.FindBy(x => x.AspNetUserId == model.UserId)?.FirstOrDefault();
    if (data != null)
    {
      ...
      await _userProfileRepository.UpdateAsync(userProfile);
      transfer.Value = true;
    }
    else
    {
      transfer.Value = false;
      transfer.Message = "Invalid User";
    }
  }
  catch (Exception ex)
  {
    transfer.ErrorMessage = ex.Message;
  }

  return transfer;
}
Sign up to request clarification or add additional context in comments.

Comments

1

The await keyword only indicates that the execution of the current function is halted until the Task which is being awaited is completed. This means if you remove the async, the method will continue execution and therefore immediately return the transfer object, even if the UpdateUserPersonalInformation Task is not finished.

Take a look at this example:

    private void showInfo()
    {
        Task.Delay(1000);
        MessageBox.Show("Info");
    }

    private async void showInfoAsync()
    {
        await Task.Delay(1000);
        MessageBox.Show("Info");
    }

In the first method, the MessageBox is immediately displayed, since the newly created Task (which only waits a specified amount of time) is not awaited. However, the second method specifies the await keyword, therefore the MessageBox is displayed only after the Task is finished (in the example, after 1000ms elapsed). But, in both cases the delay Task is ran asynchronously in the background, so the main thread (for example the UI) will not freeze.

2 Comments

What if I remove the Task as well i.e. make it synchronous. What will be the difference between both of them when it's only performing a single task?
@SalmanAkbar if the operation takes too long a synchronous function will throw a TimeOutException
0

The usage of async-await mechanism mainly used

  • when you have some long calculation process which takes some time and you want it to be on the background
  • in UI when you don't want to make the main thread stuck which will be reflected on UI performance.

you can read more here: https://learn.microsoft.com/en-us/dotnet/csharp/async

Comments

0

Time Outs

The main usages of async and await operates preventing TimeOuts by waiting for long operations to complete. However, there is another less known, but very powerful one.

If you don't await long operation, you will get a result back, such as a null, even though the actual request as not completed yet.

Cancellation Tokens

Async requests have a default parameter you can add:

public async Task<DataTransferObject<bool>> UpdatePersonalInformation(
     [FromBody] UserPersonalInformationRequestModel model,
     CancellationToken cancellationToken){..}

A CancellationToken allows the request to stop when the user changes pages or interrupts the connection. A good example of this is a user has a search box, and every time a letter is typed you filter and search results from your API. Now imagine the user types a very long string with say 15 characters. That means that 15 requests are sent and 15 requests need to be completed. Even if the front end is not awaiting the first 14 results, the API is still doing all the 15 requests.

A cancellation token simply tells the API to drop the unused threads.

Comments

0

I would like to chime in on this because most answers although good, do not point to a definite time when to use and when not. From my experience, if you are developing anything with a front-end, add async/await to your methods when expecting output from other threads to be input to your UI. This is the best strategy for handling multithread output and Microsoft should be commended to come out with this when they did. Without async/await you would have to add more code to handle thread output to UI (e.g Event, Event Handler, Delegate, Event Subscription, Marshaller). Don't need it anywhere else except if using strategically for slow peripherals.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.