2

I've seen some posts about async and await and how these actually work, but I'm still a little confused. Suppose I have two async methods and I want to make sure that the second one starts after the first one is finished. For instance consider something like this:

    public async Task MyMethod(Item x)
    {
        await AddRequest(x); // 1. Add an item asynchronously 

        // make sure 2 starts after 1 completes

        await GetAllRequest(); // 2. get all items asynchronously 
    }

Then, what is the proper way of making sure this happens?

Update:

In order to try to provide a Minimal, Complete, and Verifiable example:

I have 2 WCF services in a WPF application to communicate with Oracle WebCenter Content(UCM). Here is the minimal version of my code behind:

UCM Service to add new customer:

    public static async Task<ServiceResult> CheckInCustomer(Customer c)
    {
        CheckInSoapClient client = new CheckInSoapClient();
        using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
        {
                // an async method in Oracle WebContent services to insert new content
                result = await client.CheckInUniversalAsync(c);
        }
        return new ServiceResult();
    }

UCM Service to get all customer:

    public static async Task<Tuple<ServiceResult, QuickSearchResponse>> GetAllCustomers()
    {
        ServiceResult error;
        var result = new QuickSearchResponse();
        SearchSoapClient client = new SearchSoapClient();
        using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
        {
                // an async method in Oracle WebContent services to search for contents
                result = await client.QuickSearchAsync(queryString);
        }
            return new Tuple<ServiceResult, QuickSearchResponse>(error, result);
    }

Add Customer Async method which is binded to a Button's command in UI:

    private async Task AddCustomer()
    {
        var result = await CheckInCustomer(NewCustomer);
        if (!result.HasError)
            await GetAllCustomers();
    }

    public ICommand AddCustomerCommand
    {
        get
        {
            _addCustomerCommand = new RelayCommand(async param => await AddCustomer(), null);
        }
    }

Get all Customer Async method (Items is binded to a DataGrid in UI):

    private async Task GetAllCustomers()
    {
        Items.Clear();
        var searchResult = await GetCustomersInfoAsync();
        if (!searchResult.HasError)
        {
            foreach (var item in searchResult)
                Items.Add(new CustomerVm(item));
        }
    }

Now, when I add a new Customer, I expect to see the newly created item in the DataGrid as I first insert the customer and then get all the customers. But this code behaves in a random manner, meaning that sometimes the list shows the newly created customer a few seconds after the insertion and sometimes doesn't.

15
  • 2
    After using await you will not recieve a task, but the result of the task. await will asynchronously wait until the task is finished. Commented Jan 6, 2018 at 8:49
  • As I know await doesn't wait for the associated call to be completed, this is better to use Wait() if you want ensure t1 be completed and then t2 started. Commented Jan 6, 2018 at 8:58
  • 1
    @Aria Not true. await as the name suggests asynchronously waits for task to finish. If you don't believe me see this example Commented Jan 6, 2018 at 9:23
  • @FCin: what do you mean by asynchronously waiting? Commented Jan 6, 2018 at 9:24
  • @Bahman_Aries I'm mean that your tasks will be executed one after another without blocking. This means you don't lose responsiveness of your application. Commented Jan 6, 2018 at 9:28

2 Answers 2

4

The code your provide actually does what you want.

public async Task MyMethod(Item x)
{
    await AddRequestAsync(x); 

    await GetAllRequestAsync(); 
}

But if you are talking about the unpredictable "very very short" delay between them and you want to make sure there is no delay, it is impossible.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks for the answer, But this doesn't work for me as right now, the second line sometimes runs first. If I understand await correctly, it schedules the run time of remaining parts of the method (i.e. AddRequestAsync) for another time and then returns the control to the calling method (which is MyMethod). So parts of the second Method (GetAllRequestAsync) can actually runs before the completion of the first method. is that right?
@Bahman_Aries: No, that's not correct. If you believe that's what you're seeing, you should provide a minimal reproducible example in your question.
"The second line sometimes runs first" - this must be a false conclusion. If you mean that GetAllRequest does not contain the previously added request it is another story. Maybe AddRequest works in fire and forget mode and returns before actually processing the request. But it's really hard to tell without seeing the actual implementation.
@taffer, I'm sure you are right about the false conclusion, But I dont know what I'm doing wrong. I've provided some more details.
@Bahman_Aries: I disagree. You just need to take the database parts out and replace them with hard-coded data. This sort of "divide and conquer" to work out where the problem lies is a core part of software engineering - and definitely a core part of presenting a good question on Stack Overflow.
|
3

Await - (preferred, must be used over ContinueWith)(TY to @Taffer and @Michael comments) waits for newly created task to finish and ensures continuation once execution of waiting task is finished.

Your first func AddRequest will provide the result before moving to GetAllRequest.

public async Task MyMethod(Item x)
{
    await AddRequest(x);
    await GetAllRequest();
}

what I don't understand here is that asynchronous means the first method can be left unfinished and the execution of the main task continues. So it's possible that some parts of the second method runs before the completion of the first method.

It’s called asynchronous programming because runtime capture state of program when it encounter await keyword (which is similar to yield in iterator) and restore state back once waited task finish so the continuation runs on correct context..

But if you want to run it only after first task this is something you could do.

Use ContinueWith - its method available on the task which allows executing code after task finished execution. In simple word it allows continuation.

public async Task MyMethod(Item x)
{
    var req = AddRequest(x).ContinueWith(async (t1) =>
               {
                  await GetAllRequest();
               }); 
}

4 Comments

Since .NET 4.5 ContinueWith is deprecated in favor of await.
@taffer Await is favored but I am working on .NET 4.5.2 and I haven't seen any warning or any mention of it in the docs and we are using continue with in a few places in our projects.
@Hey24sheep You're still allowed to use ContinueWith but just calling await is preferred.
@MichaelPuckettII Oh okay and yea, I know await is preferred. Thanks

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.