Migrate from backgroundworker to async / await met

2019-05-16 11:57发布

问题:

I have been using in a WinForms C# application BackgroundWorkers to do any WCF service data calls like below:

private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            switch (_workerType)
            {
                case "search":


                    Data.SeekWCF seekWcf = new Data.SeekWCF();
                    _ds = seekWcf.SearchInvoiceAdmin(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
                    seekWcf.Dispose();

                    break;

                case "update":

                    Data.AccountingWCF accWcf = new Data.AccountingWCF();
                    _returnVal = accWcf.UpdateInvoiceAdmin(_ds);
                    accWcf.Dispose();

                    break;
            }
        }

In order to call the background worker I do for example:

private void btnSearch_Click(object sender, EventArgs e)
        {
            if (!_worker.IsBusy)
                {

                    ShowPleaseWait(Translate("Searching data. Please wait..."));
                    _workerType = "search";
                    _worker.RunWorkerAsync();
                }
        }

Now, I would like to start migrating to Task (async / await) C# 5.0, so what I did in this example was:

private async void ProcessSearch()
        {

            Data.SeekWCF seekWcf = new Data.SeekWCF();
            _ds = seekWcf.SearchInvoiceAdmin(new Guid(cboEmployer.Value.ToString()), new Guid(cboGroup.Value.ToString()), txtSearchInvoiceNumber.Text, chkSearchLike.Checked, txtSearchFolio.Text, Convert.ToInt32(txtYear.Value));
            seekWcf.Dispose();
        }

But here I get a message saying that "this async method lacks 'await' operators and will run synchronously".

Any clue on how is the best practice and the right way to do what I want to accomplish?

回答1:

Ideally, your WCF service wrapper should have Async versions of its methods, i.e. SearchInvoiceAdminAsync. Then you'd await for it:

        private async Task ProcessSearchAsync()
        {

            Data.SeekWCF 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();
        }

EDITED: A different matter is that eventually you'd need to call your async method from a regular method, e.g, upon a button click, and perhaps do something when the task is done. Here is a very simplistic scenario:

// UI Thread

Task _pendingTask = null;

void button_click()
{
    if ( _pendingTask != null)
    {
        MessageBox.Show("Still working!");
    }
    else
    {
        _pendingTask = ProcessSearchAsync();


        _pendingTask.ContinueWith((t) =>
        {
            MessageBox.Show("Task is done!");
            // check _pendingTask.IsFaulted here
            _pendingTask = null;
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
}

EDITED: Note, initially I forgot to specify TaskScheduler when calling ContinueWith. That might have resulted in continuationAction being called on a pool thread.