How to wait while they wait / asynchronous methods will finish

I have the following Async method:

private async void ProcessSearch() { // get catalogs on first search if (_invoiceTypes == null && _invoiceAccounts == null) { var confWcf = new Data.ConfigurationWCF(); _invoiceTypes = await confWcf.GetInvoiceTypesAsync(MainForm.State.Entity); _invoiceAccounts = await confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity); confWcf.Dispose(); } var seekWcf = new DataSeekWCF(); _ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value)); seekWcf.Dispose(); if (_ds != null) { SetupInvoiceGrid(); } } 

I do not want to run SetupInvoiceGrid until _invoiceTypes, _invoiceAccounts, and _ds are complete.

Any clue? Am I doing it right? Should I use Task instead of waiting?




I came up with this code that seems to work and looks good to me, but really don't know if this is correct:

 private void btnSearch_Click(object sender, EventArgs e) { lock (lockObj) { if (_isBusy) return; else _isBusy = true; } ShowPleaseWait(Translate("Searching data. Please wait...")); if (_invoiceTypes == null && _invoiceAccounts == null) { var t = GetCatalogs(); t.ContinueWith(t2 => { if (t.IsCompleted) ProcessSearch(); }); } else { ProcessSearch(); } } private async Task GetCatalogs() { // get catalogs on first search Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF(); var task1 = confWcf.GetInvoiceTypesAsync(1); var task2 = confWcf.GetInvoiceAccountsAsync(1); confWcf.Dispose(); await Task.WhenAll(task1, task2); _invoiceTypes = task1.Result; _invoiceAccounts = task2.Result; if (_invoiceTypes != null) { cboInvoiceType.DataSource = _invoiceTypes.Tables["invoice_types"]; cboInvoiceType.DisplayMember = "description"; cboInvoiceType.ValueMember = "code"; } } private async void ProcessSearch() { var seekWcf = new Data.SeekWCF(); _ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value)); seekWcf.Dispose(); if (_ds != null) { SetupInvoiceGrid(); } HidePleaseWait(); } cboEmployer.Value.ToString ()), new Guid (cboGroup.Value.ToString ()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32 (txtYear.Value private void btnSearch_Click(object sender, EventArgs e) { lock (lockObj) { if (_isBusy) return; else _isBusy = true; } ShowPleaseWait(Translate("Searching data. Please wait...")); if (_invoiceTypes == null && _invoiceAccounts == null) { var t = GetCatalogs(); t.ContinueWith(t2 => { if (t.IsCompleted) ProcessSearch(); }); } else { ProcessSearch(); } } private async Task GetCatalogs() { // get catalogs on first search Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF(); var task1 = confWcf.GetInvoiceTypesAsync(1); var task2 = confWcf.GetInvoiceAccountsAsync(1); confWcf.Dispose(); await Task.WhenAll(task1, task2); _invoiceTypes = task1.Result; _invoiceAccounts = task2.Result; if (_invoiceTypes != null) { cboInvoiceType.DataSource = _invoiceTypes.Tables["invoice_types"]; cboInvoiceType.DisplayMember = "description"; cboInvoiceType.ValueMember = "code"; } } private async void ProcessSearch() { var seekWcf = new Data.SeekWCF(); _ds = await seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value)); seekWcf.Dispose(); if (_ds != null) { SetupInvoiceGrid(); } HidePleaseWait(); } 
+4
multithreading c # task-parallel-library async-await
Aug 17 '13 at 17:03
source share
2 answers

I answered the original (?) Question about how to deal with the end of ProcessSearchAsync here .

To run tasks in parallel (as indicated in the comments), your code has been modified here, it is a bit more complicated due to invoiceTypes == null and _invoiceAccounts == null checks. Please note that the verification method below changes the logic a bit (earlier it called WCF calls only if both _invoiceTypes and _invoiceAccounts were empty - what if only one of them is null?):

 private async Task ProcessSearchAsync() { Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF(); Task</*typeof _invoiceTypes*/> t1; Task</*typeof _invoiceAccounts*/> t2; if (_invoiceTypes == null) t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity); else { var tsc1 = new TaskCompletionSource</*typeof _invoiceTypes*/>(); t1 = tsc1.Task; tsc1.SetResult(_invoiceTypes); } if ( _invoiceAccounts == null ) t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity); else { var tsc2 = new TaskCompletionSource</*typeof _invoiceAccounts*/>(); t2 = tsc2.Task; tsc2.SetResult(_invoiceAccounts); } DataSeekWCF seekWcf = new DataSeekWCF(); Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value)); await Task.WhenAll(new Task[] {t1, t2, t3}); _invoiceTypes = t1.Result; _invoiceAccounts = t2.Result; ds = t3.Result; if (_ds != null) { SetupInvoiceGrid(); } confWcf.Dispose(); seekWcf.Dispose(); } 
+3
Aug 17 '13 at 17:21
source share

Minor changes in what you have will do what you want. You can start new tasks, and then do other things, and then wait before continuing. As @Noseratio explained, this snippet below is not ready for production, because I do not check for error conditions (e.g. null links, etc.). The fact is that you can concisely and elegantly do this in parallel, without resorting to using a very large number of API tasks. One of the corrections that I deserve is that you want to move calls to Dispose to continue (i.e., after all your await s), because if you try Dispose right after calling * Async methods, you stand a good chance kill your WCF clients halfway to getting a response, and awaits are likely to throw exceptions (which I won't catch).

 private async void ProcessSearchAsync() { Data.ConfigurationWCF confWcf = new Data.ConfigurationWCF(); Task</*typeof _invoiceTypes*/> t1; Task</*typeof _invoiceAccounts*/> t2; // get catalogs on first search if (_invoiceTypes == null && _invoiceAccounts == null) { t1 = confWcf.GetInvoiceTypesAsync(MainForm.State.Entity); t2 = confWcf.GetInvoiceAccountsAsync(MainForm.State.Entity); } DataSeekWCF seekWcf = new DataSeekWCF(); Task</*typeof _ds*/> t3 = seekWcf.SearchInvoiceAdminAsync(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value)); _invoiceTypes = await t1; _invoiceAccounts = await t2; _ds = await t3; if (_ds != null) { SetupInvoiceGrid(); } confWcf.Dispose(); seekWcf.Dispose(); } 
0
Aug 17 '13 at 17:44
source share