简体   繁体   中英

C# How to make sure one async method executes after another async method

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.

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.

Await - (Preffered, 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 dont 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();
               }); 
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM